wineoss: Get rid of %ll printf formats.
[wine/multimedia.git] / dlls / localspl / provider.c
blob322418804c39000bed9e577b722e21b0312a68b1
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(LPWSTR filename, apd_data_t *apd)
217 LPWSTR ptr;
218 LPWSTR srcname;
219 DWORD res;
221 apd->src[apd->srclen] = '\0';
222 apd->dst[apd->dstlen] = '\0';
224 if (!filename || !filename[0]) {
225 /* nothing to copy */
226 return TRUE;
229 ptr = strrchrW(filename, '\\');
230 if (ptr) {
231 ptr++;
233 else
235 ptr = filename;
238 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
239 /* we have an absolute Path */
240 srcname = filename;
242 else
244 srcname = apd->src;
245 lstrcatW(srcname, ptr);
247 lstrcatW(apd->dst, ptr);
249 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
251 /* FIXME: handle APD_COPY_NEW_FILES */
252 res = CopyFileW(srcname, apd->dst, FALSE);
253 TRACE("got %u with %u\n", res, GetLastError());
255 return (apd->lazy) ? TRUE : res;
258 /******************************************************************
259 * copy_servername_from_name (internal)
261 * for an external server, the serverpart from the name is copied.
263 * RETURNS
264 * the length (in WCHAR) of the serverpart (0 for the local computer)
265 * (-length), when the name is to long
268 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
270 LPCWSTR server;
271 LPWSTR ptr;
272 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
273 DWORD len;
274 DWORD serverlen;
276 if (target) *target = '\0';
278 if (name == NULL) return 0;
279 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
281 server = &name[2];
282 /* skip over both backslash, find separator '\' */
283 ptr = strchrW(server, '\\');
284 serverlen = (ptr) ? ptr - server : lstrlenW(server);
286 /* servername is empty */
287 if (serverlen == 0) return 0;
289 TRACE("found %s\n", debugstr_wn(server, serverlen));
291 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
293 if (target) {
294 memcpy(target, server, serverlen * sizeof(WCHAR));
295 target[serverlen] = '\0';
298 len = sizeof(buffer) / sizeof(buffer[0]);
299 if (GetComputerNameW(buffer, &len)) {
300 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
301 /* The requested Servername is our computername */
302 return 0;
305 return serverlen;
308 /******************************************************************
309 * get_basename_from_name (internal)
311 * skip over the serverpart from the full name
314 static LPCWSTR get_basename_from_name(LPCWSTR name)
316 if (name == NULL) return NULL;
317 if ((name[0] == '\\') && (name[1] == '\\')) {
318 /* skip over the servername and search for the following '\' */
319 name = strchrW(&name[2], '\\');
320 if ((name) && (name[1])) {
321 /* found a separator ('\') followed by a name:
322 skip over the separator and return the rest */
323 name++;
325 else
327 /* no basename present (we found only a servername) */
328 return NULL;
331 return name;
334 /******************************************************************
335 * monitor_unload [internal]
337 * release a printmonitor and unload it from memory, when needed
340 static void monitor_unload(monitor_t * pm)
342 if (pm == NULL) return;
343 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
345 EnterCriticalSection(&monitor_handles_cs);
347 if (pm->refcount) pm->refcount--;
349 if (pm->refcount == 0) {
350 list_remove(&pm->entry);
351 FreeLibrary(pm->hdll);
352 heap_free(pm->name);
353 heap_free(pm->dllname);
354 heap_free(pm);
356 LeaveCriticalSection(&monitor_handles_cs);
359 /******************************************************************
360 * monitor_unloadall [internal]
362 * release all registered printmonitors and unload them from memory, when needed
366 static void monitor_unloadall(void)
368 monitor_t * pm;
369 monitor_t * next;
371 EnterCriticalSection(&monitor_handles_cs);
372 /* iterate through the list, with safety against removal */
373 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
375 /* skip monitorui dlls */
376 if (pm->monitor) monitor_unload(pm);
378 LeaveCriticalSection(&monitor_handles_cs);
381 /******************************************************************
382 * monitor_load [internal]
384 * load a printmonitor, get the dllname from the registry, when needed
385 * initialize the monitor and dump found function-pointers
387 * On failure, SetLastError() is called and NULL is returned
390 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
392 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
393 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
394 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
395 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
396 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
398 monitor_t * pm = NULL;
399 monitor_t * cursor;
400 LPWSTR regroot = NULL;
401 LPWSTR driver = dllname;
403 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
404 /* Is the Monitor already loaded? */
405 EnterCriticalSection(&monitor_handles_cs);
407 if (name) {
408 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
410 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
411 pm = cursor;
412 break;
417 if (pm == NULL) {
418 pm = heap_alloc_zero(sizeof(monitor_t));
419 if (pm == NULL) goto cleanup;
420 list_add_tail(&monitor_handles, &pm->entry);
422 pm->refcount++;
424 if (pm->name == NULL) {
425 /* Load the monitor */
426 LPMONITOREX pmonitorEx;
427 DWORD len;
429 if (name) {
430 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
431 regroot = heap_alloc(len * sizeof(WCHAR));
434 if (regroot) {
435 lstrcpyW(regroot, monitorsW);
436 lstrcatW(regroot, name);
437 /* Get the Driver from the Registry */
438 if (driver == NULL) {
439 HKEY hroot;
440 DWORD namesize;
441 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
442 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
443 &namesize) == ERROR_SUCCESS) {
444 driver = heap_alloc(namesize);
445 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
447 RegCloseKey(hroot);
452 pm->name = strdupW(name);
453 pm->dllname = strdupW(driver);
455 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
456 monitor_unload(pm);
457 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
458 pm = NULL;
459 goto cleanup;
462 pm->hdll = LoadLibraryW(driver);
463 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
465 if (pm->hdll == NULL) {
466 monitor_unload(pm);
467 SetLastError(ERROR_MOD_NOT_FOUND);
468 pm = NULL;
469 goto cleanup;
472 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
473 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
474 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
475 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
476 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
479 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
480 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
481 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
482 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
483 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
485 if (pInitializePrintMonitorUI != NULL) {
486 pm->monitorUI = pInitializePrintMonitorUI();
487 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
488 if (pm->monitorUI) {
489 TRACE("0x%08x: dwMonitorSize (%d)\n",
490 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
495 if (pInitializePrintMonitor && regroot) {
496 pmonitorEx = pInitializePrintMonitor(regroot);
497 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
498 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
500 if (pmonitorEx) {
501 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
502 pm->monitor = &(pmonitorEx->Monitor);
506 if (pm->monitor) {
507 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
511 if (!pm->monitor && regroot) {
512 if (pInitializePrintMonitor2 != NULL) {
513 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
515 if (pInitializeMonitorEx != NULL) {
516 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
518 if (pInitializeMonitor != NULL) {
519 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
522 if (!pm->monitor && !pm->monitorUI) {
523 monitor_unload(pm);
524 SetLastError(ERROR_PROC_NOT_FOUND);
525 pm = NULL;
528 cleanup:
529 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
530 pm->refcount++;
531 pm_localport = pm;
533 LeaveCriticalSection(&monitor_handles_cs);
534 if (driver != dllname) heap_free(driver);
535 heap_free(regroot);
536 TRACE("=> %p\n", pm);
537 return pm;
540 /******************************************************************
541 * monitor_loadall [internal]
543 * Load all registered monitors
546 static DWORD monitor_loadall(void)
548 monitor_t * pm;
549 DWORD registered = 0;
550 DWORD loaded = 0;
551 HKEY hmonitors;
552 WCHAR buffer[MAX_PATH];
553 DWORD id = 0;
555 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
556 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
557 NULL, NULL, NULL, NULL, NULL);
559 TRACE("%d monitors registered\n", registered);
561 while (id < registered) {
562 buffer[0] = '\0';
563 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
564 pm = monitor_load(buffer, NULL);
565 if (pm) loaded++;
566 id++;
568 RegCloseKey(hmonitors);
570 TRACE("%d monitors loaded\n", loaded);
571 return loaded;
574 /******************************************************************
575 * monitor_loadui [internal]
577 * load the userinterface-dll for a given portmonitor
579 * On failure, NULL is returned
581 static monitor_t * monitor_loadui(monitor_t * pm)
583 monitor_t * pui = NULL;
584 WCHAR buffer[MAX_PATH];
585 HANDLE hXcv;
586 DWORD len;
587 DWORD res;
589 if (pm == NULL) return NULL;
590 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
592 /* Try the Portmonitor first; works for many monitors */
593 if (pm->monitorUI) {
594 EnterCriticalSection(&monitor_handles_cs);
595 pm->refcount++;
596 LeaveCriticalSection(&monitor_handles_cs);
597 return pm;
600 /* query the userinterface-dllname from the Portmonitor */
601 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
602 /* building (",XcvMonitor %s",pm->name) not needed yet */
603 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
604 TRACE("got %u with %p\n", res, hXcv);
605 if (res) {
606 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
607 TRACE("got %u with %s\n", res, debugstr_w(buffer));
608 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
609 pm->monitor->pfnXcvClosePort(hXcv);
612 return pui;
615 /******************************************************************
616 * monitor_load_by_port [internal]
618 * load a printmonitor for a given port
620 * On failure, NULL is returned
623 static monitor_t * monitor_load_by_port(LPCWSTR portname)
625 HKEY hroot;
626 HKEY hport;
627 LPWSTR buffer;
628 monitor_t * pm = NULL;
629 DWORD registered = 0;
630 DWORD id = 0;
631 DWORD len;
633 TRACE("(%s)\n", debugstr_w(portname));
635 /* Try the Local Monitor first */
636 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
637 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
638 /* found the portname */
639 RegCloseKey(hroot);
640 return monitor_load(localportW, NULL);
642 RegCloseKey(hroot);
645 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
646 buffer = heap_alloc(len * sizeof(WCHAR));
647 if (buffer == NULL) return NULL;
649 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
650 EnterCriticalSection(&monitor_handles_cs);
651 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
653 while ((pm == NULL) && (id < registered)) {
654 buffer[0] = '\0';
655 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
656 TRACE("testing %s\n", debugstr_w(buffer));
657 len = lstrlenW(buffer);
658 lstrcatW(buffer, bs_ports_bsW);
659 lstrcatW(buffer, portname);
660 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
661 RegCloseKey(hport);
662 buffer[len] = '\0'; /* use only the Monitor-Name */
663 pm = monitor_load(buffer, NULL);
665 id++;
667 LeaveCriticalSection(&monitor_handles_cs);
668 RegCloseKey(hroot);
670 heap_free(buffer);
671 return pm;
674 /******************************************************************
675 * Return the number of bytes for an multi_sz string.
676 * The result includes all \0s
677 * (specifically the extra \0, that is needed as multi_sz terminator).
679 static int multi_sz_lenW(const WCHAR *str)
681 const WCHAR *ptr = str;
682 if (!str) return 0;
685 ptr += lstrlenW(ptr) + 1;
686 } while (*ptr);
688 return (ptr - str + 1) * sizeof(WCHAR);
691 /******************************************************************
692 * validate_envW [internal]
694 * validate the user-supplied printing-environment
696 * PARAMS
697 * env [I] PTR to Environment-String or NULL
699 * RETURNS
700 * Success: PTR to printenv_t
701 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
703 * NOTES
704 * An empty string is handled the same way as NULL.
708 static const printenv_t * validate_envW(LPCWSTR env)
710 const printenv_t *result = NULL;
711 unsigned int i;
713 TRACE("(%s)\n", debugstr_w(env));
714 if (env && env[0])
716 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
718 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
720 result = all_printenv[i];
721 break;
724 if (result == NULL) {
725 FIXME("unsupported Environment: %s\n", debugstr_w(env));
726 SetLastError(ERROR_INVALID_ENVIRONMENT);
728 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
730 else
732 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
735 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
736 return result;
739 /*****************************************************************************
740 * enumerate the local monitors (INTERNAL)
742 * returns the needed size (in bytes) for pMonitors
743 * and *lpreturned is set to number of entries returned in pMonitors
745 * Language-Monitors are also installed in the same Registry-Location but
746 * they are filtered in Windows (not returned by EnumMonitors).
747 * We do no filtering to simplify our Code.
750 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
752 HKEY hroot = NULL;
753 HKEY hentry = NULL;
754 LPWSTR ptr;
755 LPMONITOR_INFO_2W mi;
756 WCHAR buffer[MAX_PATH];
757 WCHAR dllname[MAX_PATH];
758 DWORD dllsize;
759 DWORD len;
760 DWORD index = 0;
761 DWORD needed = 0;
762 DWORD numentries;
763 DWORD entrysize;
765 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
767 numentries = *lpreturned; /* this is 0, when we scan the registry */
768 len = entrysize * numentries;
769 ptr = (LPWSTR) &pMonitors[len];
771 numentries = 0;
772 len = sizeof(buffer)/sizeof(buffer[0]);
773 buffer[0] = '\0';
775 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
776 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
777 /* Scan all Monitor-Registry-Keys */
778 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
779 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
780 dllsize = sizeof(dllname);
781 dllname[0] = '\0';
783 /* The Monitor must have a Driver-DLL */
784 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
785 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
786 /* We found a valid DLL for this Monitor. */
787 TRACE("using Driver: %s\n", debugstr_w(dllname));
789 RegCloseKey(hentry);
792 /* Windows returns only Port-Monitors here, but to simplify our code,
793 we do no filtering for Language-Monitors */
794 if (dllname[0]) {
795 numentries++;
796 needed += entrysize;
797 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
798 if (level > 1) {
799 /* we install and return only monitors for "Windows NT x86" */
800 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
801 needed += dllsize;
804 /* required size is calculated. Now fill the user-buffer */
805 if (pMonitors && (cbBuf >= needed)){
806 mi = (LPMONITOR_INFO_2W) pMonitors;
807 pMonitors += entrysize;
809 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
810 mi->pName = ptr;
811 lstrcpyW(ptr, buffer); /* Name of the Monitor */
812 ptr += (len+1); /* len is lstrlenW(monitorname) */
813 if (level > 1) {
814 mi->pEnvironment = ptr;
815 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
816 ptr += (lstrlenW(x86_envnameW)+1);
818 mi->pDLLName = ptr;
819 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
820 ptr += (dllsize / sizeof(WCHAR));
824 index++;
825 len = sizeof(buffer)/sizeof(buffer[0]);
826 buffer[0] = '\0';
828 RegCloseKey(hroot);
830 *lpreturned = numentries;
831 TRACE("need %d byte for %d entries\n", needed, numentries);
832 return needed;
835 /*****************************************************************************
836 * enumerate the local print processors (INTERNAL)
838 * returns the needed size (in bytes) for pPPInfo
839 * and *lpreturned is set to number of entries returned in pPPInfo
842 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
844 HKEY hroot = NULL;
845 HKEY hentry = NULL;
846 LPWSTR ptr;
847 PPRINTPROCESSOR_INFO_1W ppi;
848 WCHAR buffer[MAX_PATH];
849 WCHAR dllname[MAX_PATH];
850 DWORD dllsize;
851 DWORD len;
852 DWORD index = 0;
853 DWORD needed = 0;
854 DWORD numentries;
856 numentries = *lpreturned; /* this is 0, when we scan the registry */
857 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
858 ptr = (LPWSTR) &pPPInfo[len];
860 numentries = 0;
861 len = sizeof(buffer)/sizeof(buffer[0]);
862 buffer[0] = '\0';
864 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
865 /* add "winprint" first */
866 numentries++;
867 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
868 if (pPPInfo && (cbBuf >= needed)){
869 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
870 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
872 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
873 ppi->pName = ptr;
874 lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
875 ptr += sizeof(winprintW) / sizeof(WCHAR);
878 /* Scan all Printprocessor Keys */
879 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
880 (lstrcmpiW(buffer, winprintW) != 0)) {
881 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
882 dllsize = sizeof(dllname);
883 dllname[0] = '\0';
885 /* The Print Processor must have a Driver-DLL */
886 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
887 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
888 /* We found a valid DLL for this Print Processor */
889 TRACE("using Driver: %s\n", debugstr_w(dllname));
891 RegCloseKey(hentry);
894 if (dllname[0]) {
895 numentries++;
896 needed += sizeof(PRINTPROCESSOR_INFO_1W);
897 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
899 /* required size is calculated. Now fill the user-buffer */
900 if (pPPInfo && (cbBuf >= needed)){
901 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
902 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
904 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
905 ppi->pName = ptr;
906 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
907 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
910 index++;
911 len = sizeof(buffer)/sizeof(buffer[0]);
912 buffer[0] = '\0';
914 RegCloseKey(hroot);
916 *lpreturned = numentries;
917 TRACE("need %d byte for %d entries\n", needed, numentries);
918 return needed;
921 /******************************************************************
922 * enumerate the local Ports from all loaded monitors (internal)
924 * returns the needed size (in bytes) for pPorts
925 * and *lpreturned is set to number of entries returned in pPorts
928 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
930 monitor_t * pm;
931 LPWSTR ptr;
932 LPPORT_INFO_2W cache;
933 LPPORT_INFO_2W out;
934 LPBYTE pi_buffer = NULL;
935 DWORD pi_allocated = 0;
936 DWORD pi_needed;
937 DWORD pi_index;
938 DWORD pi_returned;
939 DWORD res;
940 DWORD outindex = 0;
941 DWORD needed;
942 DWORD numentries;
943 DWORD entrysize;
946 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
947 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
949 numentries = *lpreturned; /* this is 0, when we scan the registry */
950 needed = entrysize * numentries;
951 ptr = (LPWSTR) &pPorts[needed];
953 numentries = 0;
954 needed = 0;
956 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
958 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
959 pi_needed = 0;
960 pi_returned = 0;
961 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
962 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
963 /* Do not use heap_realloc (we do not need the old data in the buffer) */
964 heap_free(pi_buffer);
965 pi_buffer = heap_alloc(pi_needed);
966 pi_allocated = (pi_buffer) ? pi_needed : 0;
967 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
969 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
970 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
972 numentries += pi_returned;
973 needed += pi_needed;
975 /* fill the output-buffer (pPorts), if we have one */
976 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
977 pi_index = 0;
978 while (pi_returned > pi_index) {
979 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
980 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
981 out->pPortName = ptr;
982 lstrcpyW(ptr, cache->pPortName);
983 ptr += (lstrlenW(ptr)+1);
984 if (level > 1) {
985 out->pMonitorName = ptr;
986 lstrcpyW(ptr, cache->pMonitorName);
987 ptr += (lstrlenW(ptr)+1);
989 out->pDescription = ptr;
990 lstrcpyW(ptr, cache->pDescription);
991 ptr += (lstrlenW(ptr)+1);
992 out->fPortType = cache->fPortType;
993 out->Reserved = cache->Reserved;
995 pi_index++;
996 outindex++;
1001 /* the temporary portinfo-buffer is no longer needed */
1002 heap_free(pi_buffer);
1004 *lpreturned = numentries;
1005 TRACE("need %d byte for %d entries\n", needed, numentries);
1006 return needed;
1010 /*****************************************************************************
1011 * open_driver_reg [internal]
1013 * opens the registry for the printer drivers depending on the given input
1014 * variable pEnvironment
1016 * RETURNS:
1017 * Success: the opened hkey
1018 * Failure: NULL
1020 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1022 HKEY retval = NULL;
1023 LPWSTR buffer;
1024 const printenv_t * env;
1026 TRACE("(%s)\n", debugstr_w(pEnvironment));
1028 env = validate_envW(pEnvironment);
1029 if (!env) return NULL;
1031 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1032 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1034 if (buffer) {
1035 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1036 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1037 HeapFree(GetProcessHeap(), 0, buffer);
1039 return retval;
1042 /*****************************************************************************
1043 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1045 * Return the PATH for the Printer-Drivers
1047 * PARAMS
1048 * pName [I] Servername (NT only) or NULL (local Computer)
1049 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1050 * Level [I] Structure-Level (must be 1)
1051 * pDriverDirectory [O] PTR to Buffer that receives the Result
1052 * cbBuf [I] Size of Buffer at pDriverDirectory
1053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1054 * required for pDriverDirectory
1056 * RETURNS
1057 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1058 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1059 * if cbBuf is too small
1061 * Native Values returned in pDriverDirectory on Success:
1062 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1063 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1064 *| win9x(Windows 4.0): "%winsysdir%"
1066 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1069 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1070 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1072 DWORD needed;
1073 const printenv_t * env;
1075 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1076 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1078 if (pName != NULL && pName[0]) {
1079 FIXME("server %s not supported\n", debugstr_w(pName));
1080 SetLastError(ERROR_INVALID_PARAMETER);
1081 return FALSE;
1084 env = validate_envW(pEnvironment);
1085 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1088 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1089 needed = GetSystemDirectoryW(NULL, 0);
1090 /* add the Size for the Subdirectories */
1091 needed += lstrlenW(spooldriversW);
1092 needed += lstrlenW(env->subdir);
1093 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1095 *pcbNeeded = needed;
1097 if (needed > cbBuf) {
1098 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1099 return FALSE;
1102 if (pDriverDirectory == NULL) {
1103 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1104 SetLastError(ERROR_INVALID_USER_BUFFER);
1105 return FALSE;
1108 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1109 /* add the Subdirectories */
1110 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1111 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1113 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1114 return TRUE;
1117 /******************************************************************
1118 * driver_load [internal]
1120 * load a driver user interface dll
1122 * On failure, NULL is returned
1126 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1128 WCHAR fullname[MAX_PATH];
1129 HMODULE hui;
1130 DWORD len;
1132 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1134 /* build the driverdir */
1135 len = sizeof(fullname) -
1136 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1138 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1139 (LPBYTE) fullname, len, &len)) {
1140 /* Should never Fail */
1141 SetLastError(ERROR_BUFFER_OVERFLOW);
1142 return NULL;
1145 lstrcatW(fullname, env->versionsubdir);
1146 lstrcatW(fullname, backslashW);
1147 lstrcatW(fullname, dllname);
1149 hui = LoadLibraryW(fullname);
1150 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1152 return hui;
1155 /******************************************************************
1156 * printer_free
1157 * free the data pointer of an opened printer
1159 static VOID printer_free(printer_t * printer)
1161 if (printer->hXcv)
1162 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1164 monitor_unload(printer->pm);
1166 heap_free(printer->printername);
1167 heap_free(printer->name);
1168 heap_free(printer);
1171 /******************************************************************
1172 * printer_alloc_handle
1173 * alloc a printer handle and remember the data pointer in the printer handle table
1176 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1178 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1179 printer_t *printer = NULL;
1180 LPCWSTR printername;
1181 HKEY hkeyPrinters;
1182 HKEY hkeyPrinter;
1183 DWORD len;
1185 if (copy_servername_from_name(name, servername)) {
1186 FIXME("server %s not supported\n", debugstr_w(servername));
1187 SetLastError(ERROR_INVALID_PRINTER_NAME);
1188 return NULL;
1191 printername = get_basename_from_name(name);
1192 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1194 /* an empty printername is invalid */
1195 if (printername && (!printername[0])) {
1196 SetLastError(ERROR_INVALID_PARAMETER);
1197 return NULL;
1200 printer = heap_alloc_zero(sizeof(printer_t));
1201 if (!printer) goto end;
1203 /* clone the base name. This is NULL for the printserver */
1204 printer->printername = strdupW(printername);
1206 /* clone the full name */
1207 printer->name = strdupW(name);
1208 if (name && (!printer->name)) {
1209 printer_free(printer);
1210 printer = NULL;
1212 if (printername) {
1213 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1214 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1215 /* OpenPrinter(",XcvMonitor ", ...) detected */
1216 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1217 printer->pm = monitor_load(&printername[len], NULL);
1218 if (printer->pm == NULL) {
1219 printer_free(printer);
1220 SetLastError(ERROR_UNKNOWN_PORT);
1221 printer = NULL;
1222 goto end;
1225 else
1227 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1228 if (strncmpW( printername, XcvPortW, len) == 0) {
1229 /* OpenPrinter(",XcvPort ", ...) detected */
1230 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1231 printer->pm = monitor_load_by_port(&printername[len]);
1232 if (printer->pm == NULL) {
1233 printer_free(printer);
1234 SetLastError(ERROR_UNKNOWN_PORT);
1235 printer = NULL;
1236 goto end;
1241 if (printer->pm) {
1242 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1243 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1244 pDefault ? pDefault->DesiredAccess : 0,
1245 &printer->hXcv);
1247 if (printer->hXcv == NULL) {
1248 printer_free(printer);
1249 SetLastError(ERROR_INVALID_PARAMETER);
1250 printer = NULL;
1251 goto end;
1254 else
1256 /* Does the Printer exist? */
1257 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1258 ERR("Can't create Printers key\n");
1259 printer_free(printer);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME);
1261 printer = NULL;
1262 goto end;
1264 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1265 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1266 RegCloseKey(hkeyPrinters);
1267 printer_free(printer);
1268 SetLastError(ERROR_INVALID_PRINTER_NAME);
1269 printer = NULL;
1270 goto end;
1272 RegCloseKey(hkeyPrinter);
1273 RegCloseKey(hkeyPrinters);
1276 else
1278 TRACE("using the local printserver\n");
1281 end:
1283 TRACE("==> %p\n", printer);
1284 return (HANDLE)printer;
1288 /******************************************************************************
1289 * myAddPrinterDriverEx [internal]
1291 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1292 * and a special mode with lazy error checking.
1295 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1297 const printenv_t *env;
1298 apd_data_t apd;
1299 DRIVER_INFO_8W di;
1300 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1301 HMODULE hui;
1302 LPWSTR ptr;
1303 HKEY hroot;
1304 HKEY hdrv;
1305 DWORD disposition;
1306 DWORD len;
1307 LONG lres;
1308 BOOL res;
1310 /* we need to set all entries in the Registry, independent from the Level of
1311 DRIVER_INFO, that the caller supplied */
1313 ZeroMemory(&di, sizeof(di));
1314 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1315 memcpy(&di, pDriverInfo, di_sizeof[level]);
1318 /* dump the most used infos */
1319 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1320 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1321 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1322 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1323 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1324 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1325 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1326 /* dump only the first of the additional Files */
1327 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1330 /* check environment */
1331 env = validate_envW(di.pEnvironment);
1332 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1334 /* fill the copy-data / get the driverdir */
1335 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1336 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1337 (LPBYTE) apd.src, len, &len)) {
1338 /* Should never Fail */
1339 return FALSE;
1341 memcpy(apd.dst, apd.src, len);
1342 lstrcatW(apd.src, backslashW);
1343 apd.srclen = lstrlenW(apd.src);
1344 lstrcatW(apd.dst, env->versionsubdir);
1345 lstrcatW(apd.dst, backslashW);
1346 apd.dstlen = lstrlenW(apd.dst);
1347 apd.copyflags = dwFileCopyFlags;
1348 apd.lazy = lazy;
1349 CreateDirectoryW(apd.src, NULL);
1350 CreateDirectoryW(apd.dst, NULL);
1352 hroot = open_driver_reg(env->envname);
1353 if (!hroot) {
1354 ERR("Can't create Drivers key\n");
1355 return FALSE;
1358 /* Fill the Registry for the Driver */
1359 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1360 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1361 &hdrv, &disposition)) != ERROR_SUCCESS) {
1363 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1364 RegCloseKey(hroot);
1365 SetLastError(lres);
1366 return FALSE;
1368 RegCloseKey(hroot);
1370 if (disposition == REG_OPENED_EXISTING_KEY) {
1371 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1372 RegCloseKey(hdrv);
1373 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1374 return FALSE;
1377 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1378 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1379 sizeof(DWORD));
1381 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1382 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1383 apd_copyfile(di.pDriverPath, &apd);
1385 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1386 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1387 apd_copyfile(di.pDataFile, &apd);
1389 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1390 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1391 apd_copyfile(di.pConfigFile, &apd);
1393 /* settings for level 3 */
1394 if (di.pHelpFile)
1395 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1396 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1397 else
1398 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1399 apd_copyfile(di.pHelpFile, &apd);
1402 ptr = di.pDependentFiles;
1403 if (ptr)
1404 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1405 multi_sz_lenW(di.pDependentFiles));
1406 else
1407 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1408 while ((ptr != NULL) && (ptr[0])) {
1409 if (apd_copyfile(ptr, &apd)) {
1410 ptr += lstrlenW(ptr) + 1;
1412 else
1414 WARN("Failed to copy %s\n", debugstr_w(ptr));
1415 ptr = NULL;
1418 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1419 if (di.pMonitorName)
1420 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1421 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1422 else
1423 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1425 if (di.pDefaultDataType)
1426 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1427 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1428 else
1429 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1431 /* settings for level 4 */
1432 if (di.pszzPreviousNames)
1433 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1434 multi_sz_lenW(di.pszzPreviousNames));
1435 else
1436 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1438 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1440 RegCloseKey(hdrv);
1441 hui = driver_load(env, di.pConfigFile);
1442 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1443 if (hui && pDrvDriverEvent) {
1445 /* Support for DrvDriverEvent is optional */
1446 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1447 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1448 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1449 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1451 FreeLibrary(hui);
1453 TRACE("=> TRUE with %u\n", GetLastError());
1454 return TRUE;
1458 /******************************************************************************
1459 * fpAddMonitor [exported through PRINTPROVIDOR]
1461 * Install a Printmonitor
1463 * PARAMS
1464 * pName [I] Servername or NULL (local Computer)
1465 * Level [I] Structure-Level (Must be 2)
1466 * pMonitors [I] PTR to MONITOR_INFO_2
1468 * RETURNS
1469 * Success: TRUE
1470 * Failure: FALSE
1472 * NOTES
1473 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1476 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1478 monitor_t * pm = NULL;
1479 LPMONITOR_INFO_2W mi2w;
1480 HKEY hroot = NULL;
1481 HKEY hentry = NULL;
1482 DWORD disposition;
1483 BOOL res = FALSE;
1485 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1486 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1487 debugstr_w(mi2w ? mi2w->pName : NULL),
1488 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1489 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1491 if (copy_servername_from_name(pName, NULL)) {
1492 FIXME("server %s not supported\n", debugstr_w(pName));
1493 SetLastError(ERROR_ACCESS_DENIED);
1494 return FALSE;
1497 if (!mi2w->pName || (! mi2w->pName[0])) {
1498 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1499 SetLastError(ERROR_INVALID_PARAMETER);
1500 return FALSE;
1502 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1503 WARN("Environment %s requested (we support only %s)\n",
1504 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1505 SetLastError(ERROR_INVALID_ENVIRONMENT);
1506 return FALSE;
1509 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1510 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1511 SetLastError(ERROR_INVALID_PARAMETER);
1512 return FALSE;
1515 /* Load and initialize the monitor. SetLastError() is called on failure */
1516 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1517 return FALSE;
1519 monitor_unload(pm);
1521 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1523 return FALSE;
1526 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1527 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1528 &disposition) == ERROR_SUCCESS) {
1530 /* Some installers set options for the port before calling AddMonitor.
1531 We query the "Driver" entry to verify that the monitor is installed,
1532 before we return an error.
1533 When a user installs two print monitors at the same time with the
1534 same name, a race condition is possible but silently ignored. */
1536 DWORD namesize = 0;
1538 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1539 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1540 &namesize) == ERROR_SUCCESS)) {
1541 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1542 /* 9x use ERROR_ALREADY_EXISTS */
1543 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1545 else
1547 INT len;
1548 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1549 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1550 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1552 RegCloseKey(hentry);
1555 RegCloseKey(hroot);
1556 return (res);
1559 /******************************************************************************
1560 * fpAddPort [exported through PRINTPROVIDOR]
1562 * Add a Port for a specific Monitor
1564 * PARAMS
1565 * pName [I] Servername or NULL (local Computer)
1566 * hWnd [I] Handle to parent Window for the Dialog-Box
1567 * pMonitorName [I] Name of the Monitor that manage the Port
1569 * RETURNS
1570 * Success: TRUE
1571 * Failure: FALSE
1574 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1576 monitor_t * pm;
1577 monitor_t * pui;
1578 LONG lres;
1579 DWORD res;
1581 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1583 lres = copy_servername_from_name(pName, NULL);
1584 if (lres) {
1585 FIXME("server %s not supported\n", debugstr_w(pName));
1586 SetLastError(ERROR_INVALID_PARAMETER);
1587 return FALSE;
1590 /* an empty Monitorname is Invalid */
1591 if (!pMonitorName[0]) {
1592 SetLastError(ERROR_NOT_SUPPORTED);
1593 return FALSE;
1596 pm = monitor_load(pMonitorName, NULL);
1597 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
1598 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
1599 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1601 else
1603 pui = monitor_loadui(pm);
1604 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1605 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1606 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1608 else
1610 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1611 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1612 pui, debugstr_w(pui ? pui->dllname : NULL));
1614 SetLastError(ERROR_NOT_SUPPORTED);
1615 res = FALSE;
1617 monitor_unload(pui);
1619 monitor_unload(pm);
1621 TRACE("returning %d with %u\n", res, GetLastError());
1622 return res;
1625 /******************************************************************************
1626 * fpAddPortEx [exported through PRINTPROVIDOR]
1628 * Add a Port for a specific Monitor, without presenting a user interface
1630 * PARAMS
1631 * pName [I] Servername or NULL (local Computer)
1632 * level [I] Structure-Level (1 or 2) for pBuffer
1633 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1634 * pMonitorName [I] Name of the Monitor that manage the Port
1636 * RETURNS
1637 * Success: TRUE
1638 * Failure: FALSE
1641 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1643 PORT_INFO_2W * pi2;
1644 monitor_t * pm;
1645 DWORD lres;
1646 DWORD res;
1648 pi2 = (PORT_INFO_2W *) pBuffer;
1650 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1651 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1652 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1653 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1655 lres = copy_servername_from_name(pName, NULL);
1656 if (lres) {
1657 FIXME("server %s not supported\n", debugstr_w(pName));
1658 SetLastError(ERROR_INVALID_PARAMETER);
1659 return FALSE;
1662 if ((level < 1) || (level > 2)) {
1663 SetLastError(ERROR_INVALID_LEVEL);
1664 return FALSE;
1667 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1668 SetLastError(ERROR_INVALID_PARAMETER);
1669 return FALSE;
1672 /* load the Monitor */
1673 pm = monitor_load(pMonitorName, NULL);
1674 if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
1675 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
1676 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1678 else
1680 FIXME("not implemented for %s (monitor %p: %s)\n",
1681 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : NULL);
1682 SetLastError(ERROR_INVALID_PARAMETER);
1683 res = FALSE;
1685 monitor_unload(pm);
1686 return res;
1689 /******************************************************************************
1690 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1692 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1694 * PARAMS
1695 * pName [I] Servername or NULL (local Computer)
1696 * level [I] Level for the supplied DRIVER_INFO_*W struct
1697 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1698 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1700 * RESULTS
1701 * Success: TRUE
1702 * Failure: FALSE
1705 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1707 LONG lres;
1709 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1710 lres = copy_servername_from_name(pName, NULL);
1711 if (lres) {
1712 FIXME("server %s not supported\n", debugstr_w(pName));
1713 SetLastError(ERROR_ACCESS_DENIED);
1714 return FALSE;
1717 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1718 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1721 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1724 /******************************************************************************
1725 * fpClosePrinter [exported through PRINTPROVIDOR]
1727 * Close a printer handle and free associated resources
1729 * PARAMS
1730 * hPrinter [I] Printerhandle to close
1732 * RESULTS
1733 * Success: TRUE
1734 * Failure: FALSE
1737 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1739 printer_t *printer = (printer_t *) hPrinter;
1741 TRACE("(%p)\n", hPrinter);
1743 if (printer) {
1744 printer_free(printer);
1745 return TRUE;
1747 return FALSE;
1750 /******************************************************************************
1751 * fpConfigurePort [exported through PRINTPROVIDOR]
1753 * Display the Configuration-Dialog for a specific Port
1755 * PARAMS
1756 * pName [I] Servername or NULL (local Computer)
1757 * hWnd [I] Handle to parent Window for the Dialog-Box
1758 * pPortName [I] Name of the Port, that should be configured
1760 * RETURNS
1761 * Success: TRUE
1762 * Failure: FALSE
1765 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1767 monitor_t * pm;
1768 monitor_t * pui;
1769 LONG lres;
1770 DWORD res;
1772 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1774 lres = copy_servername_from_name(pName, NULL);
1775 if (lres) {
1776 FIXME("server %s not supported\n", debugstr_w(pName));
1777 SetLastError(ERROR_INVALID_NAME);
1778 return FALSE;
1781 /* an empty Portname is Invalid, but can popup a Dialog */
1782 if (!pPortName[0]) {
1783 SetLastError(ERROR_NOT_SUPPORTED);
1784 return FALSE;
1787 pm = monitor_load_by_port(pPortName);
1788 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1789 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1790 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1791 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1792 TRACE("got %d with %u\n", res, GetLastError());
1794 else
1796 pui = monitor_loadui(pm);
1797 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1798 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1799 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1800 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1801 TRACE("got %d with %u\n", res, GetLastError());
1803 else
1805 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1806 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1807 pui, debugstr_w(pui ? pui->dllname : NULL));
1809 SetLastError(ERROR_NOT_SUPPORTED);
1810 res = FALSE;
1812 monitor_unload(pui);
1814 monitor_unload(pm);
1816 TRACE("returning %d with %u\n", res, GetLastError());
1817 return res;
1820 /******************************************************************
1821 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1823 * Delete a specific Printmonitor from a Printing-Environment
1825 * PARAMS
1826 * pName [I] Servername or NULL (local Computer)
1827 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1828 * pMonitorName [I] Name of the Monitor, that should be deleted
1830 * RETURNS
1831 * Success: TRUE
1832 * Failure: FALSE
1834 * NOTES
1835 * pEnvironment is ignored in Windows for the local Computer.
1839 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1841 HKEY hroot = NULL;
1842 LONG lres;
1844 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1845 debugstr_w(pMonitorName));
1847 lres = copy_servername_from_name(pName, NULL);
1848 if (lres) {
1849 FIXME("server %s not supported\n", debugstr_w(pName));
1850 SetLastError(ERROR_INVALID_NAME);
1851 return FALSE;
1854 /* pEnvironment is ignored in Windows for the local Computer */
1855 if (!pMonitorName || !pMonitorName[0]) {
1856 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1857 SetLastError(ERROR_INVALID_PARAMETER);
1858 return FALSE;
1861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1862 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1863 return FALSE;
1866 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1867 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1868 RegCloseKey(hroot);
1869 return TRUE;
1872 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1873 RegCloseKey(hroot);
1875 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1876 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1877 return FALSE;
1880 /*****************************************************************************
1881 * fpDeletePort [exported through PRINTPROVIDOR]
1883 * Delete a specific Port
1885 * PARAMS
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1890 * RETURNS
1891 * Success: TRUE
1892 * Failure: FALSE
1895 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1897 monitor_t * pm;
1898 monitor_t * pui;
1899 LONG lres;
1900 DWORD res;
1902 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1904 lres = copy_servername_from_name(pName, NULL);
1905 if (lres) {
1906 FIXME("server %s not supported\n", debugstr_w(pName));
1907 SetLastError(ERROR_INVALID_NAME);
1908 return FALSE;
1911 /* an empty Portname is Invalid */
1912 if (!pPortName[0]) {
1913 SetLastError(ERROR_NOT_SUPPORTED);
1914 return FALSE;
1917 pm = monitor_load_by_port(pPortName);
1918 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1919 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1920 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1921 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1922 TRACE("got %d with %u\n", res, GetLastError());
1924 else
1926 pui = monitor_loadui(pm);
1927 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1928 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1929 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1930 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1931 TRACE("got %d with %u\n", res, GetLastError());
1933 else
1935 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1936 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1937 pui, debugstr_w(pui ? pui->dllname : NULL));
1939 SetLastError(ERROR_NOT_SUPPORTED);
1940 res = FALSE;
1942 monitor_unload(pui);
1944 monitor_unload(pm);
1946 TRACE("returning %d with %u\n", res, GetLastError());
1947 return res;
1950 /*****************************************************************************
1951 * fpEnumMonitors [exported through PRINTPROVIDOR]
1953 * Enumerate available Port-Monitors
1955 * PARAMS
1956 * pName [I] Servername or NULL (local Computer)
1957 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1958 * pMonitors [O] PTR to Buffer that receives the Result
1959 * cbBuf [I] Size of Buffer at pMonitors
1960 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1961 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1967 * NOTES
1968 * Windows reads the Registry once and cache the Results.
1971 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1972 LPDWORD pcbNeeded, LPDWORD pcReturned)
1974 DWORD numentries = 0;
1975 DWORD needed = 0;
1976 LONG lres;
1977 BOOL res = FALSE;
1979 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1980 cbBuf, pcbNeeded, pcReturned);
1982 lres = copy_servername_from_name(pName, NULL);
1983 if (lres) {
1984 FIXME("server %s not supported\n", debugstr_w(pName));
1985 SetLastError(ERROR_INVALID_NAME);
1986 goto em_cleanup;
1989 if (!Level || (Level > 2)) {
1990 WARN("level (%d) is ignored in win9x\n", Level);
1991 SetLastError(ERROR_INVALID_LEVEL);
1992 return FALSE;
1995 /* Scan all Monitor-Keys */
1996 numentries = 0;
1997 needed = get_local_monitors(Level, NULL, 0, &numentries);
1999 /* we calculated the needed buffersize. now do more error-checks */
2000 if (cbBuf < needed) {
2001 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2002 goto em_cleanup;
2005 /* fill the Buffer with the Monitor-Keys */
2006 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2007 res = TRUE;
2009 em_cleanup:
2010 if (pcbNeeded) *pcbNeeded = needed;
2011 if (pcReturned) *pcReturned = numentries;
2013 TRACE("returning %d with %d (%d byte for %d entries)\n",
2014 res, GetLastError(), needed, numentries);
2016 return (res);
2019 /******************************************************************************
2020 * fpEnumPorts [exported through PRINTPROVIDOR]
2022 * Enumerate available Ports
2024 * PARAMS
2025 * pName [I] Servername or NULL (local Computer)
2026 * Level [I] Structure-Level (1 or 2)
2027 * pPorts [O] PTR to Buffer that receives the Result
2028 * cbBuf [I] Size of Buffer at pPorts
2029 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2030 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2032 * RETURNS
2033 * Success: TRUE
2034 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2037 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2038 LPDWORD pcbNeeded, LPDWORD pcReturned)
2040 DWORD needed = 0;
2041 DWORD numentries = 0;
2042 LONG lres;
2043 BOOL res = FALSE;
2045 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2046 cbBuf, pcbNeeded, pcReturned);
2048 lres = copy_servername_from_name(pName, NULL);
2049 if (lres) {
2050 FIXME("server %s not supported\n", debugstr_w(pName));
2051 SetLastError(ERROR_INVALID_NAME);
2052 goto emP_cleanup;
2055 if (!Level || (Level > 2)) {
2056 SetLastError(ERROR_INVALID_LEVEL);
2057 goto emP_cleanup;
2060 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2061 SetLastError(RPC_X_NULL_REF_POINTER);
2062 goto emP_cleanup;
2065 EnterCriticalSection(&monitor_handles_cs);
2066 monitor_loadall();
2068 /* Scan all local Ports */
2069 numentries = 0;
2070 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2072 /* we calculated the needed buffersize. now do the error-checks */
2073 if (cbBuf < needed) {
2074 monitor_unloadall();
2075 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2076 goto emP_cleanup_cs;
2078 else if (!pPorts || !pcReturned) {
2079 monitor_unloadall();
2080 SetLastError(RPC_X_NULL_REF_POINTER);
2081 goto emP_cleanup_cs;
2084 /* Fill the Buffer */
2085 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2086 res = TRUE;
2087 monitor_unloadall();
2089 emP_cleanup_cs:
2090 LeaveCriticalSection(&monitor_handles_cs);
2092 emP_cleanup:
2093 if (pcbNeeded) *pcbNeeded = needed;
2094 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2096 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2097 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2099 return (res);
2102 /*****************************************************************************
2103 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2105 * Enumerate available Print Processors
2107 * PARAMS
2108 * pName [I] Servername or NULL (local Computer)
2109 * pEnvironment [I] Printing-Environment or NULL (Default)
2110 * Level [I] Structure-Level (Only 1 is allowed)
2111 * pPPInfo [O] PTR to Buffer that receives the Result
2112 * cbBuf [I] Size of Buffer at pMonitors
2113 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2114 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2116 * RETURNS
2117 * Success: TRUE
2118 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2121 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2122 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2124 const printenv_t * env;
2125 LPWSTR regpathW = NULL;
2126 DWORD numentries = 0;
2127 DWORD needed = 0;
2128 LONG lres;
2129 BOOL res = FALSE;
2131 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2132 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2134 lres = copy_servername_from_name(pName, NULL);
2135 if (lres) {
2136 FIXME("server %s not supported\n", debugstr_w(pName));
2137 SetLastError(ERROR_INVALID_NAME);
2138 goto epp_cleanup;
2141 if (Level != 1) {
2142 SetLastError(ERROR_INVALID_LEVEL);
2143 goto epp_cleanup;
2146 env = validate_envW(pEnvironment);
2147 if (!env)
2148 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2150 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2151 (lstrlenW(env->envname) * sizeof(WCHAR)));
2153 if (!regpathW)
2154 goto epp_cleanup;
2156 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2158 /* Scan all Printprocessor-Keys */
2159 numentries = 0;
2160 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2162 /* we calculated the needed buffersize. now do more error-checks */
2163 if (cbBuf < needed) {
2164 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2165 goto epp_cleanup;
2168 /* fill the Buffer with the Printprocessor Infos */
2169 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2170 res = TRUE;
2172 epp_cleanup:
2173 heap_free(regpathW);
2174 if (pcbNeeded) *pcbNeeded = needed;
2175 if (pcReturned) *pcReturned = numentries;
2177 TRACE("returning %d with %d (%d byte for %d entries)\n",
2178 res, GetLastError(), needed, numentries);
2180 return (res);
2183 /******************************************************************************
2184 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2186 * Return the PATH for the Print-Processors
2188 * PARAMS
2189 * pName [I] Servername or NULL (this computer)
2190 * pEnvironment [I] Printing-Environment or NULL (Default)
2191 * level [I] Structure-Level (must be 1)
2192 * pPPInfo [O] PTR to Buffer that receives the Result
2193 * cbBuf [I] Size of Buffer at pPPInfo
2194 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2196 * RETURNS
2197 * Success: TRUE
2198 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2200 * Native Values returned in pPPInfo on Success for this computer:
2201 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2202 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2203 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2205 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2208 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2209 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2211 const printenv_t * env;
2212 DWORD needed;
2213 LONG lres;
2215 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2216 level, pPPInfo, cbBuf, pcbNeeded);
2218 *pcbNeeded = 0;
2219 lres = copy_servername_from_name(pName, NULL);
2220 if (lres) {
2221 FIXME("server %s not supported\n", debugstr_w(pName));
2222 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2223 return FALSE;
2226 env = validate_envW(pEnvironment);
2227 if (!env)
2228 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2230 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2231 needed = GetSystemDirectoryW(NULL, 0);
2232 /* add the Size for the Subdirectories */
2233 needed += lstrlenW(spoolprtprocsW);
2234 needed += lstrlenW(env->subdir);
2235 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2237 *pcbNeeded = needed;
2239 if (needed > cbBuf) {
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2241 return FALSE;
2244 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2245 /* add the Subdirectories */
2246 lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
2247 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2248 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2249 return TRUE;
2252 /******************************************************************************
2253 * fpOpenPrinter [exported through PRINTPROVIDOR]
2255 * Open a Printer / Printserver or a Printer-Object
2257 * PARAMS
2258 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2259 * pPrinter [O] The resulting Handle is stored here
2260 * pDefaults [I] PTR to Default Printer Settings or NULL
2262 * RETURNS
2263 * Success: TRUE
2264 * Failure: FALSE
2266 * NOTES
2267 * lpPrinterName is one of:
2268 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2269 *| Printer: "PrinterName"
2270 *| Printer-Object: "PrinterName,Job xxx"
2271 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2272 *| XcvPort: "Servername,XcvPort PortName"
2276 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2277 LPPRINTER_DEFAULTSW pDefaults)
2280 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2282 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2284 return (*pPrinter != 0);
2287 /******************************************************************************
2288 * fpXcvData [exported through PRINTPROVIDOR]
2290 * Execute commands in the Printmonitor DLL
2292 * PARAMS
2293 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2294 * pszDataName [i] Name of the command to execute
2295 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2296 * cbInputData [i] Size in Bytes of Buffer at pInputData
2297 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2298 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2299 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2300 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2302 * RETURNS
2303 * Success: TRUE
2304 * Failure: FALSE
2306 * NOTES
2307 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2308 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2310 * Minimal List of commands, that a Printmonitor DLL should support:
2312 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2313 *| "AddPort" : Add a Port
2314 *| "DeletePort": Delete a Port
2316 * Many Printmonitors support additional commands. Examples for localspl.dll:
2317 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2318 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2321 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2322 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2323 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2325 printer_t *printer = (printer_t * ) hXcv;
2327 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2328 pInputData, cbInputData, pOutputData,
2329 cbOutputData, pcbOutputNeeded, pdwStatus);
2331 if (!printer || (!printer->hXcv)) {
2332 SetLastError(ERROR_INVALID_HANDLE);
2333 return FALSE;
2336 if (!pcbOutputNeeded) {
2337 SetLastError(ERROR_INVALID_PARAMETER);
2338 return FALSE;
2341 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2342 SetLastError(RPC_X_NULL_REF_POINTER);
2343 return FALSE;
2346 *pcbOutputNeeded = 0;
2348 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
2349 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2351 return TRUE;
2354 /*****************************************************
2355 * setup_provider [internal]
2357 void setup_provider(void)
2359 static const PRINTPROVIDOR backend = {
2360 fpOpenPrinter,
2361 NULL, /* fpSetJob */
2362 NULL, /* fpGetJob */
2363 NULL, /* fpEnumJobs */
2364 NULL, /* fpAddPrinter */
2365 NULL, /* fpDeletePrinter */
2366 NULL, /* fpSetPrinter */
2367 NULL, /* fpGetPrinter */
2368 NULL, /* fpEnumPrinters */
2369 NULL, /* fpAddPrinterDriver */
2370 NULL, /* fpEnumPrinterDrivers */
2371 NULL, /* fpGetPrinterDriver */
2372 fpGetPrinterDriverDirectory,
2373 NULL, /* fpDeletePrinterDriver */
2374 NULL, /* fpAddPrintProcessor */
2375 fpEnumPrintProcessors,
2376 fpGetPrintProcessorDirectory,
2377 NULL, /* fpDeletePrintProcessor */
2378 NULL, /* fpEnumPrintProcessorDatatypes */
2379 NULL, /* fpStartDocPrinter */
2380 NULL, /* fpStartPagePrinter */
2381 NULL, /* fpWritePrinter */
2382 NULL, /* fpEndPagePrinter */
2383 NULL, /* fpAbortPrinter */
2384 NULL, /* fpReadPrinter */
2385 NULL, /* fpEndDocPrinter */
2386 NULL, /* fpAddJob */
2387 NULL, /* fpScheduleJob */
2388 NULL, /* fpGetPrinterData */
2389 NULL, /* fpSetPrinterData */
2390 NULL, /* fpWaitForPrinterChange */
2391 fpClosePrinter,
2392 NULL, /* fpAddForm */
2393 NULL, /* fpDeleteForm */
2394 NULL, /* fpGetForm */
2395 NULL, /* fpSetForm */
2396 NULL, /* fpEnumForms */
2397 fpEnumMonitors,
2398 fpEnumPorts,
2399 fpAddPort,
2400 fpConfigurePort,
2401 fpDeletePort,
2402 NULL, /* fpCreatePrinterIC */
2403 NULL, /* fpPlayGdiScriptOnPrinterIC */
2404 NULL, /* fpDeletePrinterIC */
2405 NULL, /* fpAddPrinterConnection */
2406 NULL, /* fpDeletePrinterConnection */
2407 NULL, /* fpPrinterMessageBox */
2408 fpAddMonitor,
2409 fpDeleteMonitor,
2410 NULL, /* fpResetPrinter */
2411 NULL, /* fpGetPrinterDriverEx */
2412 NULL, /* fpFindFirstPrinterChangeNotification */
2413 NULL, /* fpFindClosePrinterChangeNotification */
2414 fpAddPortEx,
2415 NULL, /* fpShutDown */
2416 NULL, /* fpRefreshPrinterChangeNotification */
2417 NULL, /* fpOpenPrinterEx */
2418 NULL, /* fpAddPrinterEx */
2419 NULL, /* fpSetPort */
2420 NULL, /* fpEnumPrinterData */
2421 NULL, /* fpDeletePrinterData */
2422 NULL, /* fpClusterSplOpen */
2423 NULL, /* fpClusterSplClose */
2424 NULL, /* fpClusterSplIsAlive */
2425 NULL, /* fpSetPrinterDataEx */
2426 NULL, /* fpGetPrinterDataEx */
2427 NULL, /* fpEnumPrinterDataEx */
2428 NULL, /* fpEnumPrinterKey */
2429 NULL, /* fpDeletePrinterDataEx */
2430 NULL, /* fpDeletePrinterKey */
2431 NULL, /* fpSeekPrinter */
2432 NULL, /* fpDeletePrinterDriverEx */
2433 NULL, /* fpAddPerMachineConnection */
2434 NULL, /* fpDeletePerMachineConnection */
2435 NULL, /* fpEnumPerMachineConnections */
2436 fpXcvData,
2437 fpAddPrinterDriverEx,
2438 NULL, /* fpSplReadPrinter */
2439 NULL, /* fpDriverUnloadComplete */
2440 NULL, /* fpGetSpoolFileInfo */
2441 NULL, /* fpCommitSpoolData */
2442 NULL, /* fpCloseSpoolFileHandle */
2443 NULL, /* fpFlushPrinter */
2444 NULL, /* fpSendRecvBidiData */
2445 NULL /* fpAddDriverCatalog */
2447 pprovider = &backend;
2451 /*****************************************************
2452 * InitializePrintProvidor (localspl.@)
2454 * Initialize the Printprovider
2456 * PARAMS
2457 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2458 * cbPrintProvidor [I] Size of Buffer in Bytes
2459 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2461 * RETURNS
2462 * Success: TRUE and pPrintProvidor filled
2463 * Failure: FALSE
2465 * NOTES
2466 * The RegistryPath should be:
2467 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2468 * but this Parameter is ignored in "localspl.dll".
2472 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2473 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2476 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2477 memcpy(pPrintProvidor, pprovider,
2478 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2480 return TRUE;