user32/tests: Test MDI child order changing caused by WM_MDINEXT.
[wine/multimedia.git] / dlls / localspl / provider.c
blob0c12a0e4c514b72166e7b5625f0b8c0e1166a2af
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 spoolW[] = {'\\','s','p','o','o','l',0};
144 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
145 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
146 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
147 static const WCHAR version0_subdirW[] = {'\\','0',0};
148 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
149 static const WCHAR version3_subdirW[] = {'\\','3',0};
150 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
151 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
152 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
153 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
158 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
159 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
160 static const WCHAR x64_subdirW[] = {'x','6','4',0};
161 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
162 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
163 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
164 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
167 static const printenv_t env_ia64 = {ia64_envnameW, ia64_subdirW, 3,
168 version3_regpathW, version3_subdirW};
170 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
171 version3_regpathW, version3_subdirW};
173 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
174 version3_regpathW, version3_subdirW};
176 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
177 version0_regpathW, version0_subdirW};
179 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
182 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
183 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
184 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
185 0, sizeof(DRIVER_INFO_8W)};
188 /******************************************************************
189 * strdupW [internal]
191 * create a copy of a unicode-string
194 static LPWSTR strdupW(LPCWSTR p)
196 LPWSTR ret;
197 DWORD len;
199 if(!p) return NULL;
200 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
201 ret = heap_alloc(len);
202 if (ret) memcpy(ret, p, len);
203 return ret;
206 /******************************************************************
207 * apd_copyfile [internal]
209 * Copy a file from the driverdirectory to the versioned directory
211 * RETURNS
212 * Success: TRUE
213 * Failure: FALSE
216 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
218 WCHAR *srcname;
219 DWORD res;
221 apd->src[apd->srclen] = '\0';
222 apd->dst[apd->dstlen] = '\0';
224 if (!pathname || !pathname[0]) {
225 /* nothing to copy */
226 return TRUE;
229 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
230 srcname = pathname;
231 else
233 srcname = apd->src;
234 strcatW( srcname, file_part );
236 strcatW( apd->dst, file_part );
238 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
240 /* FIXME: handle APD_COPY_NEW_FILES */
241 res = CopyFileW(srcname, apd->dst, FALSE);
242 TRACE("got %u with %u\n", res, GetLastError());
244 return (apd->lazy) ? TRUE : res;
247 /******************************************************************
248 * copy_servername_from_name (internal)
250 * for an external server, the serverpart from the name is copied.
252 * RETURNS
253 * the length (in WCHAR) of the serverpart (0 for the local computer)
254 * (-length), when the name is to long
257 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
259 LPCWSTR server;
260 LPWSTR ptr;
261 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
262 DWORD len;
263 DWORD serverlen;
265 if (target) *target = '\0';
267 if (name == NULL) return 0;
268 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
270 server = &name[2];
271 /* skip over both backslash, find separator '\' */
272 ptr = strchrW(server, '\\');
273 serverlen = (ptr) ? ptr - server : lstrlenW(server);
275 /* servername is empty */
276 if (serverlen == 0) return 0;
278 TRACE("found %s\n", debugstr_wn(server, serverlen));
280 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
282 if (target) {
283 memcpy(target, server, serverlen * sizeof(WCHAR));
284 target[serverlen] = '\0';
287 len = sizeof(buffer) / sizeof(buffer[0]);
288 if (GetComputerNameW(buffer, &len)) {
289 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
290 /* The requested Servername is our computername */
291 return 0;
294 return serverlen;
297 /******************************************************************
298 * get_basename_from_name (internal)
300 * skip over the serverpart from the full name
303 static LPCWSTR get_basename_from_name(LPCWSTR name)
305 if (name == NULL) return NULL;
306 if ((name[0] == '\\') && (name[1] == '\\')) {
307 /* skip over the servername and search for the following '\' */
308 name = strchrW(&name[2], '\\');
309 if ((name) && (name[1])) {
310 /* found a separator ('\') followed by a name:
311 skip over the separator and return the rest */
312 name++;
314 else
316 /* no basename present (we found only a servername) */
317 return NULL;
320 return name;
323 /******************************************************************
324 * monitor_unload [internal]
326 * release a printmonitor and unload it from memory, when needed
329 static void monitor_unload(monitor_t * pm)
331 if (pm == NULL) return;
332 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
334 EnterCriticalSection(&monitor_handles_cs);
336 if (pm->refcount) pm->refcount--;
338 if (pm->refcount == 0) {
339 list_remove(&pm->entry);
340 FreeLibrary(pm->hdll);
341 heap_free(pm->name);
342 heap_free(pm->dllname);
343 heap_free(pm);
345 LeaveCriticalSection(&monitor_handles_cs);
348 /******************************************************************
349 * monitor_unloadall [internal]
351 * release all registered printmonitors and unload them from memory, when needed
355 static void monitor_unloadall(void)
357 monitor_t * pm;
358 monitor_t * next;
360 EnterCriticalSection(&monitor_handles_cs);
361 /* iterate through the list, with safety against removal */
362 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
364 /* skip monitorui dlls */
365 if (pm->monitor) monitor_unload(pm);
367 LeaveCriticalSection(&monitor_handles_cs);
370 /******************************************************************
371 * monitor_load [internal]
373 * load a printmonitor, get the dllname from the registry, when needed
374 * initialize the monitor and dump found function-pointers
376 * On failure, SetLastError() is called and NULL is returned
379 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
381 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
382 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
383 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
384 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
385 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
387 monitor_t * pm = NULL;
388 monitor_t * cursor;
389 LPWSTR regroot = NULL;
390 LPWSTR driver = dllname;
392 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
393 /* Is the Monitor already loaded? */
394 EnterCriticalSection(&monitor_handles_cs);
396 if (name) {
397 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
399 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
400 pm = cursor;
401 break;
406 if (pm == NULL) {
407 pm = heap_alloc_zero(sizeof(monitor_t));
408 if (pm == NULL) goto cleanup;
409 list_add_tail(&monitor_handles, &pm->entry);
411 pm->refcount++;
413 if (pm->name == NULL) {
414 /* Load the monitor */
415 LPMONITOREX pmonitorEx;
416 DWORD len;
418 if (name) {
419 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
420 regroot = heap_alloc(len * sizeof(WCHAR));
423 if (regroot) {
424 lstrcpyW(regroot, monitorsW);
425 lstrcatW(regroot, name);
426 /* Get the Driver from the Registry */
427 if (driver == NULL) {
428 HKEY hroot;
429 DWORD namesize;
430 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
431 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
432 &namesize) == ERROR_SUCCESS) {
433 driver = heap_alloc(namesize);
434 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
436 RegCloseKey(hroot);
441 pm->name = strdupW(name);
442 pm->dllname = strdupW(driver);
444 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
445 monitor_unload(pm);
446 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
447 pm = NULL;
448 goto cleanup;
451 pm->hdll = LoadLibraryW(driver);
452 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
454 if (pm->hdll == NULL) {
455 monitor_unload(pm);
456 SetLastError(ERROR_MOD_NOT_FOUND);
457 pm = NULL;
458 goto cleanup;
461 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
462 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
463 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
464 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
465 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
468 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
469 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
470 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
471 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
472 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
474 if (pInitializePrintMonitorUI != NULL) {
475 pm->monitorUI = pInitializePrintMonitorUI();
476 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
477 if (pm->monitorUI) {
478 TRACE("0x%08x: dwMonitorSize (%d)\n",
479 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
484 if (pInitializePrintMonitor && regroot) {
485 pmonitorEx = pInitializePrintMonitor(regroot);
486 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
487 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
489 if (pmonitorEx) {
490 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
491 pm->monitor = &(pmonitorEx->Monitor);
495 if (pm->monitor) {
496 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
500 if (!pm->monitor && regroot) {
501 if (pInitializePrintMonitor2 != NULL) {
502 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
504 if (pInitializeMonitorEx != NULL) {
505 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
507 if (pInitializeMonitor != NULL) {
508 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
511 if (!pm->monitor && !pm->monitorUI) {
512 monitor_unload(pm);
513 SetLastError(ERROR_PROC_NOT_FOUND);
514 pm = NULL;
517 cleanup:
518 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
519 pm->refcount++;
520 pm_localport = pm;
522 LeaveCriticalSection(&monitor_handles_cs);
523 if (driver != dllname) heap_free(driver);
524 heap_free(regroot);
525 TRACE("=> %p\n", pm);
526 return pm;
529 /******************************************************************
530 * monitor_loadall [internal]
532 * Load all registered monitors
535 static DWORD monitor_loadall(void)
537 monitor_t * pm;
538 DWORD registered = 0;
539 DWORD loaded = 0;
540 HKEY hmonitors;
541 WCHAR buffer[MAX_PATH];
542 DWORD id = 0;
544 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
545 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
546 NULL, NULL, NULL, NULL, NULL);
548 TRACE("%d monitors registered\n", registered);
550 while (id < registered) {
551 buffer[0] = '\0';
552 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
553 pm = monitor_load(buffer, NULL);
554 if (pm) loaded++;
555 id++;
557 RegCloseKey(hmonitors);
559 TRACE("%d monitors loaded\n", loaded);
560 return loaded;
563 /******************************************************************
564 * monitor_loadui [internal]
566 * load the userinterface-dll for a given portmonitor
568 * On failure, NULL is returned
570 static monitor_t * monitor_loadui(monitor_t * pm)
572 monitor_t * pui = NULL;
573 WCHAR buffer[MAX_PATH];
574 HANDLE hXcv;
575 DWORD len;
576 DWORD res;
578 if (pm == NULL) return NULL;
579 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
581 /* Try the Portmonitor first; works for many monitors */
582 if (pm->monitorUI) {
583 EnterCriticalSection(&monitor_handles_cs);
584 pm->refcount++;
585 LeaveCriticalSection(&monitor_handles_cs);
586 return pm;
589 /* query the userinterface-dllname from the Portmonitor */
590 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
591 /* building (",XcvMonitor %s",pm->name) not needed yet */
592 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
593 TRACE("got %u with %p\n", res, hXcv);
594 if (res) {
595 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
596 TRACE("got %u with %s\n", res, debugstr_w(buffer));
597 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
598 pm->monitor->pfnXcvClosePort(hXcv);
601 return pui;
604 /******************************************************************
605 * monitor_load_by_port [internal]
607 * load a printmonitor for a given port
609 * On failure, NULL is returned
612 static monitor_t * monitor_load_by_port(LPCWSTR portname)
614 HKEY hroot;
615 HKEY hport;
616 LPWSTR buffer;
617 monitor_t * pm = NULL;
618 DWORD registered = 0;
619 DWORD id = 0;
620 DWORD len;
622 TRACE("(%s)\n", debugstr_w(portname));
624 /* Try the Local Monitor first */
625 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
626 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
627 /* found the portname */
628 RegCloseKey(hroot);
629 return monitor_load(localportW, NULL);
631 RegCloseKey(hroot);
634 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
635 buffer = heap_alloc(len * sizeof(WCHAR));
636 if (buffer == NULL) return NULL;
638 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
639 EnterCriticalSection(&monitor_handles_cs);
640 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
642 while ((pm == NULL) && (id < registered)) {
643 buffer[0] = '\0';
644 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
645 TRACE("testing %s\n", debugstr_w(buffer));
646 len = lstrlenW(buffer);
647 lstrcatW(buffer, bs_ports_bsW);
648 lstrcatW(buffer, portname);
649 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
650 RegCloseKey(hport);
651 buffer[len] = '\0'; /* use only the Monitor-Name */
652 pm = monitor_load(buffer, NULL);
654 id++;
656 LeaveCriticalSection(&monitor_handles_cs);
657 RegCloseKey(hroot);
659 heap_free(buffer);
660 return pm;
663 /******************************************************************
664 * Return the number of bytes for an multi_sz string.
665 * The result includes all \0s
666 * (specifically the extra \0, that is needed as multi_sz terminator).
668 static int multi_sz_lenW(const WCHAR *str)
670 const WCHAR *ptr = str;
671 if (!str) return 0;
674 ptr += lstrlenW(ptr) + 1;
675 } while (*ptr);
677 return (ptr - str + 1) * sizeof(WCHAR);
680 /******************************************************************
681 * validate_envW [internal]
683 * validate the user-supplied printing-environment
685 * PARAMS
686 * env [I] PTR to Environment-String or NULL
688 * RETURNS
689 * Success: PTR to printenv_t
690 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
692 * NOTES
693 * An empty string is handled the same way as NULL.
697 static const printenv_t * validate_envW(LPCWSTR env)
699 const printenv_t *result = NULL;
700 unsigned int i;
702 TRACE("(%s)\n", debugstr_w(env));
703 if (env && env[0])
705 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
707 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
709 result = all_printenv[i];
710 break;
713 if (result == NULL) {
714 FIXME("unsupported Environment: %s\n", debugstr_w(env));
715 SetLastError(ERROR_INVALID_ENVIRONMENT);
717 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
719 else
721 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
724 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
725 return result;
728 /*****************************************************************************
729 * enumerate the local monitors (INTERNAL)
731 * returns the needed size (in bytes) for pMonitors
732 * and *lpreturned is set to number of entries returned in pMonitors
734 * Language-Monitors are also installed in the same Registry-Location but
735 * they are filtered in Windows (not returned by EnumMonitors).
736 * We do no filtering to simplify our Code.
739 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
741 HKEY hroot = NULL;
742 HKEY hentry = NULL;
743 LPWSTR ptr;
744 LPMONITOR_INFO_2W mi;
745 WCHAR buffer[MAX_PATH];
746 WCHAR dllname[MAX_PATH];
747 DWORD dllsize;
748 DWORD len;
749 DWORD index = 0;
750 DWORD needed = 0;
751 DWORD numentries;
752 DWORD entrysize;
754 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
756 numentries = *lpreturned; /* this is 0, when we scan the registry */
757 len = entrysize * numentries;
758 ptr = (LPWSTR) &pMonitors[len];
760 numentries = 0;
761 len = sizeof(buffer)/sizeof(buffer[0]);
762 buffer[0] = '\0';
764 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
765 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
766 /* Scan all Monitor-Registry-Keys */
767 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
768 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
769 dllsize = sizeof(dllname);
770 dllname[0] = '\0';
772 /* The Monitor must have a Driver-DLL */
773 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
774 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
775 /* We found a valid DLL for this Monitor. */
776 TRACE("using Driver: %s\n", debugstr_w(dllname));
778 RegCloseKey(hentry);
781 /* Windows returns only Port-Monitors here, but to simplify our code,
782 we do no filtering for Language-Monitors */
783 if (dllname[0]) {
784 numentries++;
785 needed += entrysize;
786 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
787 if (level > 1) {
788 /* we install and return only monitors for "Windows NT x86" */
789 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
790 needed += dllsize;
793 /* required size is calculated. Now fill the user-buffer */
794 if (pMonitors && (cbBuf >= needed)){
795 mi = (LPMONITOR_INFO_2W) pMonitors;
796 pMonitors += entrysize;
798 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
799 mi->pName = ptr;
800 lstrcpyW(ptr, buffer); /* Name of the Monitor */
801 ptr += (len+1); /* len is lstrlenW(monitorname) */
802 if (level > 1) {
803 mi->pEnvironment = ptr;
804 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
805 ptr += (lstrlenW(x86_envnameW)+1);
807 mi->pDLLName = ptr;
808 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
809 ptr += (dllsize / sizeof(WCHAR));
813 index++;
814 len = sizeof(buffer)/sizeof(buffer[0]);
815 buffer[0] = '\0';
817 RegCloseKey(hroot);
819 *lpreturned = numentries;
820 TRACE("need %d byte for %d entries\n", needed, numentries);
821 return needed;
824 /*****************************************************************************
825 * enumerate the local print processors (INTERNAL)
827 * returns the needed size (in bytes) for pPPInfo
828 * and *lpreturned is set to number of entries returned in pPPInfo
831 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
833 HKEY hroot = NULL;
834 HKEY hentry = NULL;
835 LPWSTR ptr;
836 PPRINTPROCESSOR_INFO_1W ppi;
837 WCHAR buffer[MAX_PATH];
838 WCHAR dllname[MAX_PATH];
839 DWORD dllsize;
840 DWORD len;
841 DWORD index = 0;
842 DWORD needed = 0;
843 DWORD numentries;
845 numentries = *lpreturned; /* this is 0, when we scan the registry */
846 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
847 ptr = (LPWSTR) &pPPInfo[len];
849 numentries = 0;
850 len = sizeof(buffer)/sizeof(buffer[0]);
851 buffer[0] = '\0';
853 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
854 /* add "winprint" first */
855 numentries++;
856 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
857 if (pPPInfo && (cbBuf >= needed)){
858 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
859 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
861 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
862 ppi->pName = ptr;
863 lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
864 ptr += sizeof(winprintW) / sizeof(WCHAR);
867 /* Scan all Printprocessor Keys */
868 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
869 (lstrcmpiW(buffer, winprintW) != 0)) {
870 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
871 dllsize = sizeof(dllname);
872 dllname[0] = '\0';
874 /* The Print Processor must have a Driver-DLL */
875 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
876 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
877 /* We found a valid DLL for this Print Processor */
878 TRACE("using Driver: %s\n", debugstr_w(dllname));
880 RegCloseKey(hentry);
883 if (dllname[0]) {
884 numentries++;
885 needed += sizeof(PRINTPROCESSOR_INFO_1W);
886 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
888 /* required size is calculated. Now fill the user-buffer */
889 if (pPPInfo && (cbBuf >= needed)){
890 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
891 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
893 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
894 ppi->pName = ptr;
895 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
896 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
899 index++;
900 len = sizeof(buffer)/sizeof(buffer[0]);
901 buffer[0] = '\0';
903 RegCloseKey(hroot);
905 *lpreturned = numentries;
906 TRACE("need %d byte for %d entries\n", needed, numentries);
907 return needed;
910 /******************************************************************
911 * enumerate the local Ports from all loaded monitors (internal)
913 * returns the needed size (in bytes) for pPorts
914 * and *lpreturned is set to number of entries returned in pPorts
917 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
919 monitor_t * pm;
920 LPWSTR ptr;
921 LPPORT_INFO_2W cache;
922 LPPORT_INFO_2W out;
923 LPBYTE pi_buffer = NULL;
924 DWORD pi_allocated = 0;
925 DWORD pi_needed;
926 DWORD pi_index;
927 DWORD pi_returned;
928 DWORD res;
929 DWORD outindex = 0;
930 DWORD needed;
931 DWORD numentries;
932 DWORD entrysize;
935 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
936 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
938 numentries = *lpreturned; /* this is 0, when we scan the registry */
939 needed = entrysize * numentries;
940 ptr = (LPWSTR) &pPorts[needed];
942 numentries = 0;
943 needed = 0;
945 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
947 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
948 pi_needed = 0;
949 pi_returned = 0;
950 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
951 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
952 /* Do not use heap_realloc (we do not need the old data in the buffer) */
953 heap_free(pi_buffer);
954 pi_buffer = heap_alloc(pi_needed);
955 pi_allocated = (pi_buffer) ? pi_needed : 0;
956 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
958 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
959 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
961 numentries += pi_returned;
962 needed += pi_needed;
964 /* fill the output-buffer (pPorts), if we have one */
965 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
966 pi_index = 0;
967 while (pi_returned > pi_index) {
968 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
969 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
970 out->pPortName = ptr;
971 lstrcpyW(ptr, cache->pPortName);
972 ptr += (lstrlenW(ptr)+1);
973 if (level > 1) {
974 out->pMonitorName = ptr;
975 lstrcpyW(ptr, cache->pMonitorName);
976 ptr += (lstrlenW(ptr)+1);
978 out->pDescription = ptr;
979 lstrcpyW(ptr, cache->pDescription);
980 ptr += (lstrlenW(ptr)+1);
981 out->fPortType = cache->fPortType;
982 out->Reserved = cache->Reserved;
984 pi_index++;
985 outindex++;
990 /* the temporary portinfo-buffer is no longer needed */
991 heap_free(pi_buffer);
993 *lpreturned = numentries;
994 TRACE("need %d byte for %d entries\n", needed, numentries);
995 return needed;
999 /*****************************************************************************
1000 * open_driver_reg [internal]
1002 * opens the registry for the printer drivers depending on the given input
1003 * variable pEnvironment
1005 * RETURNS:
1006 * Success: the opened hkey
1007 * Failure: NULL
1009 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1011 HKEY retval = NULL;
1012 LPWSTR buffer;
1013 const printenv_t * env;
1015 TRACE("(%s)\n", debugstr_w(pEnvironment));
1017 env = validate_envW(pEnvironment);
1018 if (!env) return NULL;
1020 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1021 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1023 if (buffer) {
1024 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1025 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1026 HeapFree(GetProcessHeap(), 0, buffer);
1028 return retval;
1031 /*****************************************************************************
1032 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1034 * Return the PATH for the Printer-Drivers
1036 * PARAMS
1037 * pName [I] Servername (NT only) or NULL (local Computer)
1038 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1039 * Level [I] Structure-Level (must be 1)
1040 * pDriverDirectory [O] PTR to Buffer that receives the Result
1041 * cbBuf [I] Size of Buffer at pDriverDirectory
1042 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1043 * required for pDriverDirectory
1045 * RETURNS
1046 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1047 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1048 * if cbBuf is too small
1050 * Native Values returned in pDriverDirectory on Success:
1051 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1052 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1053 *| win9x(Windows 4.0): "%winsysdir%"
1055 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1058 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1059 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1061 DWORD needed;
1062 const printenv_t * env;
1063 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1065 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1066 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1068 if (pName != NULL && pName[0]) {
1069 FIXME("server %s not supported\n", debugstr_w(pName));
1070 SetLastError(ERROR_INVALID_PARAMETER);
1071 return FALSE;
1074 env = validate_envW(pEnvironment);
1075 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1078 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1079 needed = GetSystemDirectoryW(NULL, 0);
1080 /* add the Size for the Subdirectories */
1081 needed += lstrlenW(spoolW);
1082 needed += lstrlenW(driversW);
1083 needed += lstrlenW(env->subdir);
1084 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1086 *pcbNeeded = needed;
1088 if (needed > cbBuf) {
1089 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1090 return FALSE;
1093 if (dir == NULL) {
1094 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1095 SetLastError(ERROR_INVALID_USER_BUFFER);
1096 return FALSE;
1099 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1100 /* add the Subdirectories */
1101 lstrcatW( dir, spoolW );
1102 CreateDirectoryW( dir, NULL );
1103 lstrcatW( dir, driversW );
1104 CreateDirectoryW( dir, NULL );
1105 lstrcatW( dir, env->subdir );
1106 CreateDirectoryW( dir, NULL );
1108 TRACE( "=> %s\n", debugstr_w( dir ) );
1109 return TRUE;
1112 /******************************************************************
1113 * driver_load [internal]
1115 * load a driver user interface dll
1117 * On failure, NULL is returned
1121 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1123 WCHAR fullname[MAX_PATH];
1124 HMODULE hui;
1125 DWORD len;
1127 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1129 /* build the driverdir */
1130 len = sizeof(fullname) -
1131 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1133 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1134 (LPBYTE) fullname, len, &len)) {
1135 /* Should never Fail */
1136 SetLastError(ERROR_BUFFER_OVERFLOW);
1137 return NULL;
1140 lstrcatW(fullname, env->versionsubdir);
1141 lstrcatW(fullname, backslashW);
1142 lstrcatW(fullname, dllname);
1144 hui = LoadLibraryW(fullname);
1145 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1147 return hui;
1150 /******************************************************************
1151 * printer_free
1152 * free the data pointer of an opened printer
1154 static VOID printer_free(printer_t * printer)
1156 if (printer->hXcv)
1157 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1159 monitor_unload(printer->pm);
1161 heap_free(printer->printername);
1162 heap_free(printer->name);
1163 heap_free(printer);
1166 /******************************************************************
1167 * printer_alloc_handle
1168 * alloc a printer handle and remember the data pointer in the printer handle table
1171 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1173 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1174 printer_t *printer = NULL;
1175 LPCWSTR printername;
1176 HKEY hkeyPrinters;
1177 HKEY hkeyPrinter;
1178 DWORD len;
1180 if (copy_servername_from_name(name, servername)) {
1181 FIXME("server %s not supported\n", debugstr_w(servername));
1182 SetLastError(ERROR_INVALID_PRINTER_NAME);
1183 return NULL;
1186 printername = get_basename_from_name(name);
1187 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1189 /* an empty printername is invalid */
1190 if (printername && (!printername[0])) {
1191 SetLastError(ERROR_INVALID_PARAMETER);
1192 return NULL;
1195 printer = heap_alloc_zero(sizeof(printer_t));
1196 if (!printer) goto end;
1198 /* clone the base name. This is NULL for the printserver */
1199 printer->printername = strdupW(printername);
1201 /* clone the full name */
1202 printer->name = strdupW(name);
1203 if (name && (!printer->name)) {
1204 printer_free(printer);
1205 printer = NULL;
1207 if (printername) {
1208 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1209 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1210 /* OpenPrinter(",XcvMonitor ", ...) detected */
1211 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1212 printer->pm = monitor_load(&printername[len], NULL);
1213 if (printer->pm == NULL) {
1214 printer_free(printer);
1215 SetLastError(ERROR_UNKNOWN_PORT);
1216 printer = NULL;
1217 goto end;
1220 else
1222 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1223 if (strncmpW( printername, XcvPortW, len) == 0) {
1224 /* OpenPrinter(",XcvPort ", ...) detected */
1225 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1226 printer->pm = monitor_load_by_port(&printername[len]);
1227 if (printer->pm == NULL) {
1228 printer_free(printer);
1229 SetLastError(ERROR_UNKNOWN_PORT);
1230 printer = NULL;
1231 goto end;
1236 if (printer->pm) {
1237 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1238 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1239 pDefault ? pDefault->DesiredAccess : 0,
1240 &printer->hXcv);
1242 if (printer->hXcv == NULL) {
1243 printer_free(printer);
1244 SetLastError(ERROR_INVALID_PARAMETER);
1245 printer = NULL;
1246 goto end;
1249 else
1251 /* Does the Printer exist? */
1252 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1253 ERR("Can't create Printers key\n");
1254 printer_free(printer);
1255 SetLastError(ERROR_INVALID_PRINTER_NAME);
1256 printer = NULL;
1257 goto end;
1259 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1260 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1261 RegCloseKey(hkeyPrinters);
1262 printer_free(printer);
1263 SetLastError(ERROR_INVALID_PRINTER_NAME);
1264 printer = NULL;
1265 goto end;
1267 RegCloseKey(hkeyPrinter);
1268 RegCloseKey(hkeyPrinters);
1271 else
1273 TRACE("using the local printserver\n");
1276 end:
1278 TRACE("==> %p\n", printer);
1279 return (HANDLE)printer;
1282 static inline WCHAR *get_file_part( WCHAR *name )
1284 WCHAR *ptr = strrchrW( name, '\\' );
1285 if (ptr) return ptr + 1;
1286 return name;
1289 /******************************************************************************
1290 * myAddPrinterDriverEx [internal]
1292 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1293 * and a special mode with lazy error checking.
1296 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1298 const printenv_t *env;
1299 apd_data_t apd;
1300 DRIVER_INFO_8W di;
1301 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1302 HMODULE hui;
1303 WCHAR *file;
1304 HKEY hroot;
1305 HKEY hdrv;
1306 DWORD disposition;
1307 DWORD len;
1308 LONG lres;
1309 BOOL res;
1311 /* we need to set all entries in the Registry, independent from the Level of
1312 DRIVER_INFO, that the caller supplied */
1314 ZeroMemory(&di, sizeof(di));
1315 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1316 memcpy(&di, pDriverInfo, di_sizeof[level]);
1319 /* dump the most used infos */
1320 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1321 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1322 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1323 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1324 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1325 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1326 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1327 /* dump only the first of the additional Files */
1328 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1331 /* check environment */
1332 env = validate_envW(di.pEnvironment);
1333 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1335 /* fill the copy-data / get the driverdir */
1336 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1337 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1338 (LPBYTE) apd.src, len, &len)) {
1339 /* Should never Fail */
1340 return FALSE;
1342 memcpy(apd.dst, apd.src, len);
1343 lstrcatW(apd.src, backslashW);
1344 apd.srclen = lstrlenW(apd.src);
1345 lstrcatW(apd.dst, env->versionsubdir);
1346 lstrcatW(apd.dst, backslashW);
1347 apd.dstlen = lstrlenW(apd.dst);
1348 apd.copyflags = dwFileCopyFlags;
1349 apd.lazy = lazy;
1350 CreateDirectoryW(apd.src, NULL);
1351 CreateDirectoryW(apd.dst, NULL);
1353 hroot = open_driver_reg(env->envname);
1354 if (!hroot) {
1355 ERR("Can't create Drivers key\n");
1356 return FALSE;
1359 /* Fill the Registry for the Driver */
1360 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1361 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1362 &hdrv, &disposition)) != ERROR_SUCCESS) {
1364 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1365 RegCloseKey(hroot);
1366 SetLastError(lres);
1367 return FALSE;
1369 RegCloseKey(hroot);
1371 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1372 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1373 sizeof(DWORD));
1375 file = get_file_part( di.pDriverPath );
1376 RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1377 apd_copyfile( di.pDriverPath, file, &apd );
1379 file = get_file_part( di.pDataFile );
1380 RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1381 apd_copyfile( di.pDataFile, file, &apd );
1383 file = get_file_part( di.pConfigFile );
1384 RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1385 apd_copyfile( di.pConfigFile, file, &apd );
1387 /* settings for level 3 */
1388 if (di.pHelpFile)
1390 file = get_file_part( di.pHelpFile );
1391 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1392 apd_copyfile( di.pHelpFile, file, &apd );
1394 else
1395 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1397 if (di.pDependentFiles && *di.pDependentFiles)
1399 WCHAR *reg, *reg_ptr, *in_ptr;
1400 reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1402 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += strlenW( in_ptr ) + 1)
1404 file = get_file_part( in_ptr );
1405 len = strlenW( file ) + 1;
1406 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1407 reg_ptr += len;
1408 apd_copyfile( in_ptr, file, &apd );
1410 *reg_ptr = 0;
1412 RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1413 HeapFree( GetProcessHeap(), 0, reg );
1415 else
1416 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
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;