rasapi32: Update spec file.
[wine/zf.git] / dlls / localspl / provider.c
blob7dde72d323d1f1507b1307e88afbe2f8fe6e3354
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
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winreg.h"
29 #include "winspool.h"
30 #include "winuser.h"
31 #include "ddk/winddiui.h"
32 #include "ddk/winsplp.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
37 #include "localspl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
41 /* ############################### */
43 static CRITICAL_SECTION monitor_handles_cs;
44 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
46 0, 0, &monitor_handles_cs,
47 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
48 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
50 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
52 /* ############################### */
54 typedef struct {
55 WCHAR src[MAX_PATH+MAX_PATH];
56 WCHAR dst[MAX_PATH+MAX_PATH];
57 DWORD srclen;
58 DWORD dstlen;
59 DWORD copyflags;
60 BOOL lazy;
61 } apd_data_t;
63 typedef struct {
64 struct list entry;
65 LPWSTR name;
66 LPWSTR dllname;
67 PMONITORUI monitorUI;
68 MONITOR2 monitor;
69 BOOL (WINAPI *old_EnumPorts)(LPWSTR,DWORD,LPBYTE,DWORD,LPDWORD,LPDWORD);
70 BOOL (WINAPI *old_OpenPort)(LPWSTR,PHANDLE);
71 BOOL (WINAPI *old_OpenPortEx)(LPWSTR,LPWSTR,PHANDLE,struct _MONITOR *);
72 BOOL (WINAPI *old_AddPort)(LPWSTR,HWND,LPWSTR);
73 BOOL (WINAPI *old_AddPortEx)(LPWSTR,DWORD,LPBYTE,LPWSTR);
74 BOOL (WINAPI *old_ConfigurePort)(LPWSTR,HWND,LPWSTR);
75 BOOL (WINAPI *old_DeletePort)(LPWSTR,HWND,LPWSTR);
76 BOOL (WINAPI *old_XcvOpenPort)(LPCWSTR,ACCESS_MASK,PHANDLE);
77 HANDLE hmon;
78 HMODULE hdll;
79 DWORD refcount;
80 } monitor_t;
82 typedef struct {
83 LPCWSTR envname;
84 LPCWSTR subdir;
85 DWORD driverversion;
86 LPCWSTR versionregpath;
87 LPCWSTR versionsubdir;
88 } printenv_t;
90 typedef struct {
91 LPWSTR name;
92 LPWSTR printername;
93 monitor_t * pm;
94 HANDLE hXcv;
95 } printer_t;
97 /* ############################### */
99 static struct list monitor_handles = LIST_INIT( monitor_handles );
100 static monitor_t * pm_localport;
102 static const WCHAR fmt_driversW[] =
103 L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
104 static const WCHAR fmt_printprocessorsW[] =
105 L"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors";
106 static const WCHAR monitorsW[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
107 static const WCHAR printersW[] = L"System\\CurrentControlSet\\Control\\Print\\Printers";
108 static const WCHAR winnt_cv_portsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
109 static const WCHAR x86_envnameW[] = L"Windows NT x86";
112 static const printenv_t env_ia64 = {L"Windows IA64", L"ia64", 3,
113 L"\\Version-3", L"\\3"};
115 static const printenv_t env_x86 = {x86_envnameW, L"w32x86", 3,
116 L"\\Version-3", L"\\3"};
118 static const printenv_t env_x64 = {L"Windows x64", L"x64", 3,
119 L"\\Version-3", L"\\3"};
121 static const printenv_t env_win40 = {L"Windows 4.0", L"win40", 0,
122 L"\\Version-0", L"\\0"};
124 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
127 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
128 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
129 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
130 0, sizeof(DRIVER_INFO_8W)};
133 /******************************************************************
134 * strdupW [internal]
136 * create a copy of a unicode-string
139 static LPWSTR strdupW(LPCWSTR p)
141 LPWSTR ret;
142 DWORD len;
144 if(!p) return NULL;
145 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
146 ret = heap_alloc(len);
147 if (ret) memcpy(ret, p, len);
148 return ret;
151 /******************************************************************
152 * apd_copyfile [internal]
154 * Copy a file from the driverdirectory to the versioned directory
156 * RETURNS
157 * Success: TRUE
158 * Failure: FALSE
161 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
163 WCHAR *srcname;
164 BOOL res;
166 apd->src[apd->srclen] = '\0';
167 apd->dst[apd->dstlen] = '\0';
169 if (!pathname || !pathname[0]) {
170 /* nothing to copy */
171 return TRUE;
174 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
175 srcname = pathname;
176 else
178 srcname = apd->src;
179 lstrcatW( srcname, file_part );
181 lstrcatW( apd->dst, file_part );
183 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
185 /* FIXME: handle APD_COPY_NEW_FILES */
186 res = CopyFileW(srcname, apd->dst, FALSE);
187 TRACE("got %d with %u\n", res, GetLastError());
189 return apd->lazy || res;
192 /******************************************************************
193 * copy_servername_from_name (internal)
195 * for an external server, the serverpart from the name is copied.
197 * RETURNS
198 * the length (in WCHAR) of the serverpart (0 for the local computer)
199 * (-length), when the name is too long
202 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
204 LPCWSTR server;
205 LPWSTR ptr;
206 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
207 DWORD len;
208 DWORD serverlen;
210 if (target) *target = '\0';
212 if (name == NULL) return 0;
213 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
215 server = &name[2];
216 /* skip over both backslash, find separator '\' */
217 ptr = wcschr(server, '\\');
218 serverlen = (ptr) ? ptr - server : lstrlenW(server);
220 /* servername is empty */
221 if (serverlen == 0) return 0;
223 TRACE("found %s\n", debugstr_wn(server, serverlen));
225 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
227 if (target) {
228 memcpy(target, server, serverlen * sizeof(WCHAR));
229 target[serverlen] = '\0';
232 len = ARRAY_SIZE(buffer);
233 if (GetComputerNameW(buffer, &len)) {
234 if ((serverlen == len) && (wcsnicmp(server, buffer, len) == 0)) {
235 /* The requested Servername is our computername */
236 return 0;
239 return serverlen;
242 /******************************************************************
243 * get_basename_from_name (internal)
245 * skip over the serverpart from the full name
248 static LPCWSTR get_basename_from_name(LPCWSTR name)
250 if (name == NULL) return NULL;
251 if ((name[0] == '\\') && (name[1] == '\\')) {
252 /* skip over the servername and search for the following '\' */
253 name = wcschr(&name[2], '\\');
254 if ((name) && (name[1])) {
255 /* found a separator ('\') followed by a name:
256 skip over the separator and return the rest */
257 name++;
259 else
261 /* no basename present (we found only a servername) */
262 return NULL;
265 return name;
268 /******************************************************************
269 * monitor_unload [internal]
271 * release a printmonitor and unload it from memory, when needed
274 static void monitor_unload(monitor_t * pm)
276 if (pm == NULL) return;
277 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
279 EnterCriticalSection(&monitor_handles_cs);
281 if (pm->refcount) pm->refcount--;
283 if (pm->refcount == 0) {
284 list_remove(&pm->entry);
286 if (pm->monitor.pfnShutdown)
287 pm->monitor.pfnShutdown(pm->hmon);
289 FreeLibrary(pm->hdll);
290 heap_free(pm->name);
291 heap_free(pm->dllname);
292 heap_free(pm);
294 LeaveCriticalSection(&monitor_handles_cs);
297 /******************************************************************
298 * monitor_unloadall [internal]
300 * release all registered printmonitors and unload them from memory, when needed
304 static void monitor_unloadall(void)
306 monitor_t * pm;
307 monitor_t * next;
309 EnterCriticalSection(&monitor_handles_cs);
310 /* iterate through the list, with safety against removal */
311 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
313 /* skip monitorui dlls */
314 if (pm->monitor.cbSize) monitor_unload(pm);
316 LeaveCriticalSection(&monitor_handles_cs);
319 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
320 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
321 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
323 FIXME("stub\n");
324 return ERROR_CALL_NOT_IMPLEMENTED;
327 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
328 PHANDLE phkResult, HANDLE hSpooler)
330 FIXME("stub\n");
331 return ERROR_CALL_NOT_IMPLEMENTED;
334 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
336 FIXME("stub\n");
337 return ERROR_CALL_NOT_IMPLEMENTED;
340 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
342 FIXME("stub\n");
343 return ERROR_CALL_NOT_IMPLEMENTED;
346 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
347 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
349 FIXME("stub\n");
350 return ERROR_CALL_NOT_IMPLEMENTED;
353 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
354 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
355 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
356 HANDLE hSpooler)
358 FIXME("stub\n");
359 return ERROR_CALL_NOT_IMPLEMENTED;
362 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
363 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
365 FIXME("stub\n");
366 return ERROR_CALL_NOT_IMPLEMENTED;
369 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
371 FIXME("stub\n");
372 return ERROR_CALL_NOT_IMPLEMENTED;
375 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
376 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
377 HANDLE hSpooler)
379 FIXME("stub\n");
380 return ERROR_CALL_NOT_IMPLEMENTED;
383 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
384 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
386 FIXME("stub\n");
387 return ERROR_CALL_NOT_IMPLEMENTED;
390 static MONITORREG monreg =
392 sizeof(MONITORREG),
393 CreateKey,
394 OpenKey,
395 CloseKey,
396 DeleteKey,
397 EnumKey,
398 QueryInfoKey,
399 SetValue,
400 DeleteValue,
401 EnumValue,
402 QueryValue
405 /******************************************************************
406 * monitor_load [internal]
408 * load a printmonitor, get the dllname from the registry, when needed
409 * initialize the monitor and dump found function-pointers
411 * On failure, SetLastError() is called and NULL is returned
414 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
416 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
417 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
418 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
419 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
420 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
422 monitor_t * pm = NULL;
423 monitor_t * cursor;
424 LPWSTR regroot = NULL;
425 LPWSTR driver = dllname;
426 HKEY hroot = 0;
428 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
429 /* Is the Monitor already loaded? */
430 EnterCriticalSection(&monitor_handles_cs);
432 if (name) {
433 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
435 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
436 pm = cursor;
437 break;
442 if (pm == NULL) {
443 pm = heap_alloc_zero(sizeof(monitor_t));
444 if (pm == NULL) goto cleanup;
445 list_add_tail(&monitor_handles, &pm->entry);
447 pm->refcount++;
449 if (pm->name == NULL) {
450 /* Load the monitor */
451 DWORD len;
453 if (name) {
454 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
455 regroot = heap_alloc(len * sizeof(WCHAR));
458 if (regroot) {
459 lstrcpyW(regroot, monitorsW);
460 lstrcatW(regroot, name);
461 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
462 /* Get the Driver from the Registry */
463 if (driver == NULL) {
464 DWORD namesize;
465 if (RegQueryValueExW(hroot, L"Driver", NULL, NULL, NULL,
466 &namesize) == ERROR_SUCCESS) {
467 driver = heap_alloc(namesize);
468 RegQueryValueExW(hroot, L"Driver", NULL, NULL, (BYTE*)driver, &namesize);
472 else
473 WARN("%s not found\n", debugstr_w(regroot));
476 pm->name = strdupW(name);
477 pm->dllname = strdupW(driver);
479 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
480 monitor_unload(pm);
481 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
482 pm = NULL;
483 goto cleanup;
486 pm->hdll = LoadLibraryW(driver);
487 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
489 if (pm->hdll == NULL) {
490 monitor_unload(pm);
491 SetLastError(ERROR_MOD_NOT_FOUND);
492 pm = NULL;
493 goto cleanup;
496 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
497 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
498 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
499 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
500 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
503 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
504 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
505 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
506 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
507 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
509 if (pInitializePrintMonitorUI != NULL) {
510 pm->monitorUI = pInitializePrintMonitorUI();
511 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
512 if (pm->monitorUI) {
513 TRACE("0x%08x: dwMonitorSize (%d)\n",
514 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
519 if (pInitializePrintMonitor2 && hroot) {
520 MONITORINIT init;
521 MONITOR2 *monitor2;
522 HANDLE hmon;
524 memset(&init, 0, sizeof(init));
525 init.cbSize = sizeof(init);
526 init.hckRegistryRoot = hroot;
527 init.pMonitorReg = &monreg;
528 init.bLocal = TRUE;
530 monitor2 = pInitializePrintMonitor2(&init, &hmon);
531 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
532 monitor2, debugstr_w(driver), debugstr_w(regroot));
533 if (monitor2)
535 memcpy(&pm->monitor, monitor2, min(monitor2->cbSize, sizeof(pm->monitor)));
536 pm->hmon = hmon;
539 else if (pInitializePrintMonitor && regroot) {
540 MONITOREX *pmonitorEx;
542 pmonitorEx = pInitializePrintMonitor(regroot);
543 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
544 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
545 if (pmonitorEx)
547 /* Layout of MONITOREX and MONITOR2 mostly matches */
548 memcpy(&pm->monitor, pmonitorEx, min(pmonitorEx->dwMonitorSize + sizeof(void *), sizeof(pm->monitor)));
549 /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */
550 pm->monitor.cbSize += sizeof(void *);
552 pm->old_EnumPorts = pmonitorEx->Monitor.pfnEnumPorts;
553 pm->old_OpenPort = pmonitorEx->Monitor.pfnOpenPort;
554 pm->old_OpenPortEx = pmonitorEx->Monitor.pfnOpenPortEx;
555 pm->old_AddPort = pmonitorEx->Monitor.pfnAddPort;
556 pm->old_AddPortEx = pmonitorEx->Monitor.pfnAddPortEx;
557 pm->old_ConfigurePort = pmonitorEx->Monitor.pfnConfigurePort;
558 pm->old_DeletePort = pmonitorEx->Monitor.pfnDeletePort;
559 pm->old_XcvOpenPort = pmonitorEx->Monitor.pfnXcvOpenPort;
561 pm->monitor.pfnEnumPorts = NULL;
562 pm->monitor.pfnOpenPort = NULL;
563 pm->monitor.pfnOpenPortEx = NULL;
564 pm->monitor.pfnAddPort = NULL;
565 pm->monitor.pfnAddPortEx = NULL;
566 pm->monitor.pfnConfigurePort = NULL;
567 pm->monitor.pfnDeletePort = NULL;
568 pm->monitor.pfnXcvOpenPort = NULL;
572 if (!pm->monitor.cbSize && regroot) {
573 if (pInitializeMonitorEx != NULL) {
574 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
576 if (pInitializeMonitor != NULL) {
577 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
580 if (!pm->monitor.cbSize && !pm->monitorUI) {
581 monitor_unload(pm);
582 SetLastError(ERROR_PROC_NOT_FOUND);
583 pm = NULL;
586 cleanup:
587 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, L"Local Port") == 0)) {
588 pm->refcount++;
589 pm_localport = pm;
591 LeaveCriticalSection(&monitor_handles_cs);
592 if (driver != dllname) heap_free(driver);
593 if (hroot) RegCloseKey(hroot);
594 heap_free(regroot);
595 TRACE("=> %p\n", pm);
596 return pm;
599 /******************************************************************
600 * monitor_loadall [internal]
602 * Load all registered monitors
605 static DWORD monitor_loadall(void)
607 monitor_t * pm;
608 DWORD registered = 0;
609 DWORD loaded = 0;
610 HKEY hmonitors;
611 WCHAR buffer[MAX_PATH];
612 DWORD id = 0;
614 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
615 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
616 NULL, NULL, NULL, NULL, NULL);
618 TRACE("%d monitors registered\n", registered);
620 while (id < registered) {
621 buffer[0] = '\0';
622 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
623 pm = monitor_load(buffer, NULL);
624 if (pm) loaded++;
625 id++;
627 RegCloseKey(hmonitors);
629 TRACE("%d monitors loaded\n", loaded);
630 return loaded;
633 /******************************************************************
634 * monitor_loadui [internal]
636 * load the userinterface-dll for a given portmonitor
638 * On failure, NULL is returned
640 static monitor_t * monitor_loadui(monitor_t * pm)
642 monitor_t * pui = NULL;
643 WCHAR buffer[MAX_PATH];
644 HANDLE hXcv;
645 DWORD len;
646 DWORD res = 0;
648 if (pm == NULL) return NULL;
649 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
651 /* Try the Portmonitor first; works for many monitors */
652 if (pm->monitorUI) {
653 EnterCriticalSection(&monitor_handles_cs);
654 pm->refcount++;
655 LeaveCriticalSection(&monitor_handles_cs);
656 return pm;
659 /* query the userinterface-dllname from the Portmonitor */
660 /* building (",XcvMonitor %s",pm->name) not needed yet */
661 if (pm->monitor.pfnXcvOpenPort)
662 res = pm->monitor.pfnXcvOpenPort(pm->hmon, L"", SERVER_ACCESS_ADMINISTER, &hXcv);
663 else if (pm->old_XcvOpenPort)
664 res = pm->old_XcvOpenPort(L"", SERVER_ACCESS_ADMINISTER, &hXcv);
665 TRACE("got %u with %p\n", res, hXcv);
666 if (res) {
667 res = pm->monitor.pfnXcvDataPort(hXcv, L"MonitorUI", NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
668 TRACE("got %u with %s\n", res, debugstr_w(buffer));
669 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
670 pm->monitor.pfnXcvClosePort(hXcv);
672 return pui;
675 /******************************************************************
676 * monitor_load_by_port [internal]
678 * load a printmonitor for a given port
680 * On failure, NULL is returned
683 static monitor_t * monitor_load_by_port(LPCWSTR portname)
685 HKEY hroot;
686 HKEY hport;
687 LPWSTR buffer;
688 monitor_t * pm = NULL;
689 DWORD registered = 0;
690 DWORD id = 0;
691 DWORD len;
693 TRACE("(%s)\n", debugstr_w(portname));
695 /* Try the Local Monitor first */
696 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
697 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
698 /* found the portname */
699 RegCloseKey(hroot);
700 return monitor_load(L"Local Port", NULL);
702 RegCloseKey(hroot);
705 len = MAX_PATH + lstrlenW(L"\\Ports\\") + lstrlenW(portname) + 1;
706 buffer = heap_alloc(len * sizeof(WCHAR));
707 if (buffer == NULL) return NULL;
709 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
710 EnterCriticalSection(&monitor_handles_cs);
711 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
713 while ((pm == NULL) && (id < registered)) {
714 buffer[0] = '\0';
715 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
716 TRACE("testing %s\n", debugstr_w(buffer));
717 len = lstrlenW(buffer);
718 lstrcatW(buffer, L"\\Ports\\");
719 lstrcatW(buffer, portname);
720 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
721 RegCloseKey(hport);
722 buffer[len] = '\0'; /* use only the Monitor-Name */
723 pm = monitor_load(buffer, NULL);
725 id++;
727 LeaveCriticalSection(&monitor_handles_cs);
728 RegCloseKey(hroot);
730 heap_free(buffer);
731 return pm;
734 /******************************************************************
735 * Return the number of bytes for an multi_sz string.
736 * The result includes all \0s
737 * (specifically the extra \0, that is needed as multi_sz terminator).
739 static int multi_sz_lenW(const WCHAR *str)
741 const WCHAR *ptr = str;
742 if (!str) return 0;
745 ptr += lstrlenW(ptr) + 1;
746 } while (*ptr);
748 return (ptr - str + 1) * sizeof(WCHAR);
751 /******************************************************************
752 * validate_envW [internal]
754 * validate the user-supplied printing-environment
756 * PARAMS
757 * env [I] PTR to Environment-String or NULL
759 * RETURNS
760 * Success: PTR to printenv_t
761 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
763 * NOTES
764 * An empty string is handled the same way as NULL.
768 static const printenv_t * validate_envW(LPCWSTR env)
770 const printenv_t *result = NULL;
771 unsigned int i;
773 TRACE("(%s)\n", debugstr_w(env));
774 if (env && env[0])
776 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
778 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
780 result = all_printenv[i];
781 break;
784 if (result == NULL) {
785 FIXME("unsupported Environment: %s\n", debugstr_w(env));
786 SetLastError(ERROR_INVALID_ENVIRONMENT);
788 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
790 else
792 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
795 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
796 return result;
799 /*****************************************************************************
800 * enumerate the local monitors (INTERNAL)
802 * returns the needed size (in bytes) for pMonitors
803 * and *lpreturned is set to number of entries returned in pMonitors
805 * Language-Monitors are also installed in the same Registry-Location but
806 * they are filtered in Windows (not returned by EnumMonitors).
807 * We do no filtering to simplify our Code.
810 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
812 HKEY hroot = NULL;
813 HKEY hentry = NULL;
814 LPWSTR ptr;
815 LPMONITOR_INFO_2W mi;
816 WCHAR buffer[MAX_PATH];
817 WCHAR dllname[MAX_PATH];
818 DWORD dllsize;
819 DWORD len;
820 DWORD index = 0;
821 DWORD needed = 0;
822 DWORD numentries;
823 DWORD entrysize;
825 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
827 numentries = *lpreturned; /* this is 0, when we scan the registry */
828 len = entrysize * numentries;
829 ptr = (LPWSTR) &pMonitors[len];
831 numentries = 0;
832 len = ARRAY_SIZE(buffer);
833 buffer[0] = '\0';
835 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
836 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
837 /* Scan all Monitor-Registry-Keys */
838 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
839 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
840 dllsize = sizeof(dllname);
841 dllname[0] = '\0';
843 /* The Monitor must have a Driver-DLL */
844 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
845 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
846 /* We found a valid DLL for this Monitor. */
847 TRACE("using Driver: %s\n", debugstr_w(dllname));
849 RegCloseKey(hentry);
852 /* Windows returns only Port-Monitors here, but to simplify our code,
853 we do no filtering for Language-Monitors */
854 if (dllname[0]) {
855 numentries++;
856 needed += entrysize;
857 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
858 if (level > 1) {
859 /* we install and return only monitors for "Windows NT x86" */
860 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
861 needed += dllsize;
864 /* required size is calculated. Now fill the user-buffer */
865 if (pMonitors && (cbBuf >= needed)){
866 mi = (LPMONITOR_INFO_2W) pMonitors;
867 pMonitors += entrysize;
869 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
870 mi->pName = ptr;
871 lstrcpyW(ptr, buffer); /* Name of the Monitor */
872 ptr += (len+1); /* len is lstrlenW(monitorname) */
873 if (level > 1) {
874 mi->pEnvironment = ptr;
875 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
876 ptr += (lstrlenW(x86_envnameW)+1);
878 mi->pDLLName = ptr;
879 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
880 ptr += (dllsize / sizeof(WCHAR));
884 index++;
885 len = ARRAY_SIZE(buffer);
886 buffer[0] = '\0';
888 RegCloseKey(hroot);
890 *lpreturned = numentries;
891 TRACE("need %d byte for %d entries\n", needed, numentries);
892 return needed;
895 /*****************************************************************************
896 * enumerate the local print processors (INTERNAL)
898 * returns the needed size (in bytes) for pPPInfo
899 * and *lpreturned is set to number of entries returned in pPPInfo
902 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
904 HKEY hroot = NULL;
905 HKEY hentry = NULL;
906 LPWSTR ptr;
907 PPRINTPROCESSOR_INFO_1W ppi;
908 WCHAR buffer[MAX_PATH];
909 WCHAR dllname[MAX_PATH];
910 DWORD dllsize;
911 DWORD len;
912 DWORD index = 0;
913 DWORD needed = 0;
914 DWORD numentries;
916 numentries = *lpreturned; /* this is 0, when we scan the registry */
917 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
918 ptr = (LPWSTR) &pPPInfo[len];
920 numentries = 0;
921 len = ARRAY_SIZE(buffer);
922 buffer[0] = '\0';
924 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
925 /* add "winprint" first */
926 numentries++;
927 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(L"winprint");
928 if (pPPInfo && (cbBuf >= needed)){
929 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
930 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
932 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
933 ppi->pName = ptr;
934 lstrcpyW(ptr, L"winprint"); /* Name of the Print Processor */
935 ptr += ARRAY_SIZE(L"winprint");
938 /* Scan all Printprocessor Keys */
939 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
940 (lstrcmpiW(buffer, L"winprint") != 0)) {
941 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
942 dllsize = sizeof(dllname);
943 dllname[0] = '\0';
945 /* The Print Processor must have a Driver-DLL */
946 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
947 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
948 /* We found a valid DLL for this Print Processor */
949 TRACE("using Driver: %s\n", debugstr_w(dllname));
951 RegCloseKey(hentry);
954 if (dllname[0]) {
955 numentries++;
956 needed += sizeof(PRINTPROCESSOR_INFO_1W);
957 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
959 /* required size is calculated. Now fill the user-buffer */
960 if (pPPInfo && (cbBuf >= needed)){
961 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
962 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
964 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
965 ppi->pName = ptr;
966 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
967 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
970 index++;
971 len = ARRAY_SIZE(buffer);
972 buffer[0] = '\0';
974 RegCloseKey(hroot);
976 *lpreturned = numentries;
977 TRACE("need %d byte for %d entries\n", needed, numentries);
978 return needed;
981 static BOOL wrap_EnumPorts(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer,
982 DWORD size, LPDWORD needed, LPDWORD returned)
984 if (pm->monitor.pfnEnumPorts)
985 return pm->monitor.pfnEnumPorts(pm->hmon, name, level, buffer, size, needed, returned);
987 if (pm->old_EnumPorts)
988 return pm->old_EnumPorts(name, level, buffer, size, needed, returned);
990 WARN("EnumPorts is not implemented by monitor\n");
991 return FALSE;
994 /******************************************************************
995 * enumerate the local Ports from all loaded monitors (internal)
997 * returns the needed size (in bytes) for pPorts
998 * and *lpreturned is set to number of entries returned in pPorts
1001 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1003 monitor_t * pm;
1004 LPWSTR ptr;
1005 LPPORT_INFO_2W cache;
1006 LPPORT_INFO_2W out;
1007 LPBYTE pi_buffer = NULL;
1008 DWORD pi_allocated = 0;
1009 DWORD pi_needed;
1010 DWORD pi_index;
1011 DWORD pi_returned;
1012 DWORD res;
1013 DWORD outindex = 0;
1014 DWORD needed;
1015 DWORD numentries;
1016 DWORD entrysize;
1018 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1019 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1021 numentries = *lpreturned; /* this is 0, when we scan the registry */
1022 needed = entrysize * numentries;
1023 ptr = (LPWSTR) &pPorts[needed];
1025 numentries = 0;
1026 needed = 0;
1028 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1030 if (pm->monitor.pfnEnumPorts || pm->old_EnumPorts) {
1031 pi_needed = 0;
1032 pi_returned = 0;
1033 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1034 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1035 /* Do not use heap_realloc (we do not need the old data in the buffer) */
1036 heap_free(pi_buffer);
1037 pi_buffer = heap_alloc(pi_needed);
1038 pi_allocated = (pi_buffer) ? pi_needed : 0;
1039 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1041 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
1042 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1044 numentries += pi_returned;
1045 needed += pi_needed;
1047 /* fill the output-buffer (pPorts), if we have one */
1048 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1049 pi_index = 0;
1050 while (pi_returned > pi_index) {
1051 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1052 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1053 out->pPortName = ptr;
1054 lstrcpyW(ptr, cache->pPortName);
1055 ptr += (lstrlenW(ptr)+1);
1056 if (level > 1) {
1057 out->pMonitorName = ptr;
1058 lstrcpyW(ptr, cache->pMonitorName);
1059 ptr += (lstrlenW(ptr)+1);
1061 out->pDescription = ptr;
1062 lstrcpyW(ptr, cache->pDescription);
1063 ptr += (lstrlenW(ptr)+1);
1064 out->fPortType = cache->fPortType;
1065 out->Reserved = cache->Reserved;
1067 pi_index++;
1068 outindex++;
1073 /* the temporary portinfo-buffer is no longer needed */
1074 heap_free(pi_buffer);
1076 *lpreturned = numentries;
1077 TRACE("need %d byte for %d entries\n", needed, numentries);
1078 return needed;
1082 /*****************************************************************************
1083 * open_driver_reg [internal]
1085 * opens the registry for the printer drivers depending on the given input
1086 * variable pEnvironment
1088 * RETURNS:
1089 * Success: the opened hkey
1090 * Failure: NULL
1092 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1094 HKEY retval = NULL;
1095 LPWSTR buffer;
1096 const printenv_t * env;
1098 TRACE("(%s)\n", debugstr_w(pEnvironment));
1100 env = validate_envW(pEnvironment);
1101 if (!env) return NULL;
1103 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1104 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1106 if (buffer) {
1107 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1108 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1109 HeapFree(GetProcessHeap(), 0, buffer);
1111 return retval;
1114 /*****************************************************************************
1115 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1117 * Return the PATH for the Printer-Drivers
1119 * PARAMS
1120 * pName [I] Servername (NT only) or NULL (local Computer)
1121 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1122 * Level [I] Structure-Level (must be 1)
1123 * pDriverDirectory [O] PTR to Buffer that receives the Result
1124 * cbBuf [I] Size of Buffer at pDriverDirectory
1125 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1126 * required for pDriverDirectory
1128 * RETURNS
1129 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1130 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1131 * if cbBuf is too small
1133 * Native Values returned in pDriverDirectory on Success:
1134 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1135 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1136 *| win9x(Windows 4.0): "%winsysdir%"
1138 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1141 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1142 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1144 DWORD needed;
1145 const printenv_t * env;
1146 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1148 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1149 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1151 if (pName != NULL && pName[0]) {
1152 FIXME("server %s not supported\n", debugstr_w(pName));
1153 SetLastError(ERROR_INVALID_PARAMETER);
1154 return FALSE;
1157 env = validate_envW(pEnvironment);
1158 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1161 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1162 needed = GetSystemDirectoryW(NULL, 0);
1163 /* add the Size for the Subdirectories */
1164 needed += lstrlenW(L"\\spool");
1165 needed += lstrlenW(L"\\drivers\\");
1166 needed += lstrlenW(env->subdir);
1167 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1169 *pcbNeeded = needed;
1171 if (needed > cbBuf) {
1172 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1173 return FALSE;
1176 if (dir == NULL) {
1177 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1178 SetLastError(ERROR_INVALID_USER_BUFFER);
1179 return FALSE;
1182 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1183 /* add the Subdirectories */
1184 lstrcatW( dir, L"\\spool" );
1185 CreateDirectoryW( dir, NULL );
1186 lstrcatW( dir, L"\\drivers\\" );
1187 CreateDirectoryW( dir, NULL );
1188 lstrcatW( dir, env->subdir );
1189 CreateDirectoryW( dir, NULL );
1191 TRACE( "=> %s\n", debugstr_w( dir ) );
1192 return TRUE;
1195 /******************************************************************
1196 * driver_load [internal]
1198 * load a driver user interface dll
1200 * On failure, NULL is returned
1204 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1206 WCHAR fullname[MAX_PATH];
1207 HMODULE hui;
1208 DWORD len;
1210 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1212 /* build the driverdir */
1213 len = sizeof(fullname) -
1214 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1216 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1217 (LPBYTE) fullname, len, &len)) {
1218 /* Should never fail */
1219 SetLastError(ERROR_BUFFER_OVERFLOW);
1220 return NULL;
1223 lstrcatW(fullname, env->versionsubdir);
1224 lstrcatW(fullname, L"\\");
1225 lstrcatW(fullname, dllname);
1227 hui = LoadLibraryW(fullname);
1228 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1230 return hui;
1233 /******************************************************************
1234 * printer_free
1235 * free the data pointer of an opened printer
1237 static VOID printer_free(printer_t * printer)
1239 if (printer->hXcv)
1241 if (printer->pm->monitor.pfnXcvClosePort)
1242 printer->pm->monitor.pfnXcvClosePort(printer->hXcv);
1245 monitor_unload(printer->pm);
1247 heap_free(printer->printername);
1248 heap_free(printer->name);
1249 heap_free(printer);
1252 /******************************************************************
1253 * printer_alloc_handle
1254 * alloc a printer handle and remember the data pointer in the printer handle table
1257 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1259 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1260 printer_t *printer = NULL;
1261 LPCWSTR printername;
1262 HKEY hkeyPrinters;
1263 HKEY hkeyPrinter;
1264 DWORD len;
1266 if (copy_servername_from_name(name, servername)) {
1267 FIXME("server %s not supported\n", debugstr_w(servername));
1268 SetLastError(ERROR_INVALID_PRINTER_NAME);
1269 return NULL;
1272 printername = get_basename_from_name(name);
1273 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1275 /* an empty printername is invalid */
1276 if (printername && (!printername[0])) {
1277 SetLastError(ERROR_INVALID_PARAMETER);
1278 return NULL;
1281 printer = heap_alloc_zero(sizeof(printer_t));
1282 if (!printer) goto end;
1284 /* clone the base name. This is NULL for the printserver */
1285 printer->printername = strdupW(printername);
1287 /* clone the full name */
1288 printer->name = strdupW(name);
1289 if (name && (!printer->name)) {
1290 printer_free(printer);
1291 printer = NULL;
1293 if (printername) {
1294 len = ARRAY_SIZE(L",XcvMonitor ") - 1;
1295 if (wcsncmp(printername, L",XcvMonitor ", len) == 0) {
1296 /* OpenPrinter(",XcvMonitor ", ...) detected */
1297 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1298 printer->pm = monitor_load(&printername[len], NULL);
1299 if (printer->pm == NULL) {
1300 printer_free(printer);
1301 SetLastError(ERROR_UNKNOWN_PORT);
1302 printer = NULL;
1303 goto end;
1306 else
1308 len = ARRAY_SIZE(L",XcvPort ") - 1;
1309 if (wcsncmp( printername, L",XcvPort ", len) == 0) {
1310 /* OpenPrinter(",XcvPort ", ...) detected */
1311 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1312 printer->pm = monitor_load_by_port(&printername[len]);
1313 if (printer->pm == NULL) {
1314 printer_free(printer);
1315 SetLastError(ERROR_UNKNOWN_PORT);
1316 printer = NULL;
1317 goto end;
1322 if (printer->pm) {
1323 if (printer->pm->monitor.pfnXcvOpenPort)
1324 printer->pm->monitor.pfnXcvOpenPort(printer->pm->hmon, &printername[len],
1325 pDefault ? pDefault->DesiredAccess : 0,
1326 &printer->hXcv);
1327 else if (printer->pm->old_XcvOpenPort)
1328 printer->pm->old_XcvOpenPort(&printername[len],
1329 pDefault ? pDefault->DesiredAccess : 0,
1330 &printer->hXcv);
1331 if (printer->hXcv == NULL) {
1332 printer_free(printer);
1333 SetLastError(ERROR_INVALID_PARAMETER);
1334 printer = NULL;
1335 goto end;
1338 else
1340 /* Does the Printer exist? */
1341 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1342 ERR("Can't create Printers key\n");
1343 printer_free(printer);
1344 SetLastError(ERROR_INVALID_PRINTER_NAME);
1345 printer = NULL;
1346 goto end;
1348 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1349 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1350 RegCloseKey(hkeyPrinters);
1351 printer_free(printer);
1352 SetLastError(ERROR_INVALID_PRINTER_NAME);
1353 printer = NULL;
1354 goto end;
1356 RegCloseKey(hkeyPrinter);
1357 RegCloseKey(hkeyPrinters);
1360 else
1362 TRACE("using the local printserver\n");
1365 end:
1367 TRACE("==> %p\n", printer);
1368 return (HANDLE)printer;
1371 static inline WCHAR *get_file_part( WCHAR *name )
1373 WCHAR *ptr = wcsrchr( name, '\\' );
1374 if (ptr) return ptr + 1;
1375 return name;
1378 /******************************************************************************
1379 * myAddPrinterDriverEx [internal]
1381 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1382 * and a special mode with lazy error checking.
1385 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1387 const printenv_t *env;
1388 apd_data_t apd;
1389 DRIVER_INFO_8W di;
1390 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1391 HMODULE hui;
1392 WCHAR *file;
1393 HKEY hroot;
1394 HKEY hdrv;
1395 DWORD disposition;
1396 DWORD len;
1397 LONG lres;
1398 BOOL res;
1400 /* we need to set all entries in the Registry, independent from the Level of
1401 DRIVER_INFO, that the caller supplied */
1403 ZeroMemory(&di, sizeof(di));
1404 if (pDriverInfo && (level < ARRAY_SIZE(di_sizeof))) {
1405 memcpy(&di, pDriverInfo, di_sizeof[level]);
1408 /* dump the most used infos */
1409 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1410 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1411 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1412 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1413 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1414 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1415 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1416 /* dump only the first of the additional Files */
1417 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1420 /* check environment */
1421 env = validate_envW(di.pEnvironment);
1422 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1424 /* fill the copy-data / get the driverdir */
1425 len = sizeof(apd.src) - sizeof(L"\\3") - sizeof(WCHAR);
1426 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1427 (LPBYTE) apd.src, len, &len)) {
1428 /* Should never fail */
1429 return FALSE;
1431 memcpy(apd.dst, apd.src, len);
1432 lstrcatW(apd.src, L"\\");
1433 apd.srclen = lstrlenW(apd.src);
1434 lstrcatW(apd.dst, env->versionsubdir);
1435 lstrcatW(apd.dst, L"\\");
1436 apd.dstlen = lstrlenW(apd.dst);
1437 apd.copyflags = dwFileCopyFlags;
1438 apd.lazy = lazy;
1439 CreateDirectoryW(apd.src, NULL);
1440 CreateDirectoryW(apd.dst, NULL);
1442 hroot = open_driver_reg(env->envname);
1443 if (!hroot) {
1444 ERR("Can't create Drivers key\n");
1445 return FALSE;
1448 /* Fill the Registry for the Driver */
1449 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1450 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1451 &hdrv, &disposition)) != ERROR_SUCCESS) {
1453 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1454 RegCloseKey(hroot);
1455 SetLastError(lres);
1456 return FALSE;
1458 RegCloseKey(hroot);
1460 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1461 RegSetValueExW(hdrv, L"Version", 0, REG_DWORD, (const BYTE*) &env->driverversion,
1462 sizeof(DWORD));
1464 file = get_file_part( di.pDriverPath );
1465 RegSetValueExW( hdrv, L"Driver", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1466 apd_copyfile( di.pDriverPath, file, &apd );
1468 file = get_file_part( di.pDataFile );
1469 RegSetValueExW( hdrv, L"Data File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1470 apd_copyfile( di.pDataFile, file, &apd );
1472 file = get_file_part( di.pConfigFile );
1473 RegSetValueExW( hdrv, L"Configuration File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1474 apd_copyfile( di.pConfigFile, file, &apd );
1476 /* settings for level 3 */
1477 if (di.pHelpFile)
1479 file = get_file_part( di.pHelpFile );
1480 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1481 apd_copyfile( di.pHelpFile, file, &apd );
1483 else
1484 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (const BYTE*)L"", sizeof(L"") );
1486 if (di.pDependentFiles && *di.pDependentFiles)
1488 WCHAR *reg, *reg_ptr, *in_ptr;
1489 reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1491 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += lstrlenW( in_ptr ) + 1)
1493 file = get_file_part( in_ptr );
1494 len = lstrlenW( file ) + 1;
1495 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1496 reg_ptr += len;
1497 apd_copyfile( in_ptr, file, &apd );
1499 *reg_ptr = 0;
1501 RegSetValueExW( hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (BYTE*)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1502 HeapFree( GetProcessHeap(), 0, reg );
1504 else
1505 RegSetValueExW(hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
1507 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1508 if (di.pMonitorName)
1509 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (BYTE*)di.pMonitorName,
1510 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1511 else
1512 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
1514 if (di.pDefaultDataType)
1515 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (BYTE*)di.pDefaultDataType,
1516 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1517 else
1518 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
1520 /* settings for level 4 */
1521 if (di.pszzPreviousNames)
1522 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (BYTE*)di.pszzPreviousNames,
1523 multi_sz_lenW(di.pszzPreviousNames));
1524 else
1525 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
1527 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1529 RegCloseKey(hdrv);
1530 hui = driver_load(env, di.pConfigFile);
1531 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1532 if (hui && pDrvDriverEvent) {
1534 /* Support for DrvDriverEvent is optional */
1535 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1536 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1537 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1538 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1540 FreeLibrary(hui);
1542 TRACE("=> TRUE with %u\n", GetLastError());
1543 return TRUE;
1547 /******************************************************************************
1548 * fpAddMonitor [exported through PRINTPROVIDOR]
1550 * Install a Printmonitor
1552 * PARAMS
1553 * pName [I] Servername or NULL (local Computer)
1554 * Level [I] Structure-Level (Must be 2)
1555 * pMonitors [I] PTR to MONITOR_INFO_2
1557 * RETURNS
1558 * Success: TRUE
1559 * Failure: FALSE
1561 * NOTES
1562 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1565 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1567 const printenv_t * env;
1568 monitor_t * pm = NULL;
1569 LPMONITOR_INFO_2W mi2w;
1570 HKEY hroot = NULL;
1571 HKEY hentry = NULL;
1572 DWORD disposition;
1573 BOOL res = FALSE;
1575 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1576 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1577 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
1579 if (copy_servername_from_name(pName, NULL)) {
1580 FIXME("server %s not supported\n", debugstr_w(pName));
1581 SetLastError(ERROR_ACCESS_DENIED);
1582 return FALSE;
1585 if (!mi2w->pName || (! mi2w->pName[0])) {
1586 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1587 SetLastError(ERROR_INVALID_PARAMETER);
1588 return FALSE;
1591 env = validate_envW(mi2w->pEnvironment);
1592 if (!env)
1593 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1595 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1596 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1597 SetLastError(ERROR_INVALID_PARAMETER);
1598 return FALSE;
1601 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1602 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1603 return FALSE;
1606 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1607 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1608 &disposition) == ERROR_SUCCESS) {
1610 /* Some installers set options for the port before calling AddMonitor.
1611 We query the "Driver" entry to verify that the monitor is installed,
1612 before we return an error.
1613 When a user installs two print monitors at the same time with the
1614 same name, a race condition is possible but silently ignored. */
1616 DWORD namesize = 0;
1618 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1619 (RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL,
1620 &namesize) == ERROR_SUCCESS)) {
1621 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1622 /* 9x use ERROR_ALREADY_EXISTS */
1623 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1625 else
1627 INT len;
1628 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1629 res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ,
1630 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1632 /* Load and initialize the monitor. SetLastError() is called on failure */
1633 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL)
1635 RegDeleteKeyW(hroot, mi2w->pName);
1636 res = FALSE;
1638 else
1639 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
1642 RegCloseKey(hentry);
1645 RegCloseKey(hroot);
1646 return (res);
1649 static BOOL wrap_AddPort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR monitor_name)
1651 if (pm->monitor.pfnAddPort)
1652 return pm->monitor.pfnAddPort(pm->hmon, name, hwnd, monitor_name);
1654 if (pm->old_AddPort)
1655 return pm->old_AddPort(name, hwnd, monitor_name);
1657 WARN("AddPort is not implemented by monitor\n");
1658 return FALSE;
1661 /******************************************************************************
1662 * fpAddPort [exported through PRINTPROVIDOR]
1664 * Add a Port for a specific Monitor
1666 * PARAMS
1667 * pName [I] Servername or NULL (local Computer)
1668 * hWnd [I] Handle to parent Window for the Dialog-Box
1669 * pMonitorName [I] Name of the Monitor that manage the Port
1671 * RETURNS
1672 * Success: TRUE
1673 * Failure: FALSE
1676 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1678 monitor_t * pm;
1679 monitor_t * pui;
1680 LONG lres;
1681 DWORD res;
1683 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1685 lres = copy_servername_from_name(pName, NULL);
1686 if (lres) {
1687 FIXME("server %s not supported\n", debugstr_w(pName));
1688 SetLastError(ERROR_INVALID_PARAMETER);
1689 return FALSE;
1692 /* an empty Monitorname is Invalid */
1693 if (!pMonitorName[0]) {
1694 SetLastError(ERROR_NOT_SUPPORTED);
1695 return FALSE;
1698 pm = monitor_load(pMonitorName, NULL);
1699 if (pm && (pm->monitor.pfnAddPort || pm->old_AddPort)) {
1700 res = wrap_AddPort(pm, pName, hWnd, pMonitorName);
1701 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1703 else
1705 pui = monitor_loadui(pm);
1706 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1707 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1708 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1710 else
1712 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1713 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1714 pui, debugstr_w(pui ? pui->dllname : NULL));
1716 SetLastError(ERROR_NOT_SUPPORTED);
1717 res = FALSE;
1719 monitor_unload(pui);
1721 monitor_unload(pm);
1723 TRACE("returning %d with %u\n", res, GetLastError());
1724 return res;
1727 static BOOL wrap_AddPortEx(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer, LPWSTR monitor_name)
1729 if (pm->monitor.pfnAddPortEx)
1730 return pm->monitor.pfnAddPortEx(pm->hmon, name, level, buffer, monitor_name);
1732 if (pm->old_AddPortEx)
1733 return pm->old_AddPortEx(name, level, buffer, monitor_name);
1735 WARN("AddPortEx is not implemented by monitor\n");
1736 return FALSE;
1739 /******************************************************************************
1740 * fpAddPortEx [exported through PRINTPROVIDOR]
1742 * Add a Port for a specific Monitor, without presenting a user interface
1744 * PARAMS
1745 * pName [I] Servername or NULL (local Computer)
1746 * level [I] Structure-Level (1 or 2) for pBuffer
1747 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1748 * pMonitorName [I] Name of the Monitor that manage the Port
1750 * RETURNS
1751 * Success: TRUE
1752 * Failure: FALSE
1755 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1757 PORT_INFO_2W * pi2;
1758 monitor_t * pm;
1759 DWORD lres;
1760 DWORD res;
1762 pi2 = (PORT_INFO_2W *) pBuffer;
1764 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1765 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1766 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1767 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1769 lres = copy_servername_from_name(pName, NULL);
1770 if (lres) {
1771 FIXME("server %s not supported\n", debugstr_w(pName));
1772 SetLastError(ERROR_INVALID_PARAMETER);
1773 return FALSE;
1776 if ((level < 1) || (level > 2)) {
1777 SetLastError(ERROR_INVALID_LEVEL);
1778 return FALSE;
1781 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1782 SetLastError(ERROR_INVALID_PARAMETER);
1783 return FALSE;
1786 /* load the Monitor */
1787 pm = monitor_load(pMonitorName, NULL);
1788 if (pm && (pm->monitor.pfnAddPortEx || pm->old_AddPortEx))
1790 res = wrap_AddPortEx(pm, pName, level, pBuffer, pMonitorName);
1791 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1793 else
1795 FIXME("not implemented for %s (monitor %p: %s)\n",
1796 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
1797 SetLastError(ERROR_INVALID_PARAMETER);
1798 res = FALSE;
1800 monitor_unload(pm);
1801 return res;
1804 /******************************************************************************
1805 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1807 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1809 * PARAMS
1810 * pName [I] Servername or NULL (local Computer)
1811 * level [I] Level for the supplied DRIVER_INFO_*W struct
1812 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1813 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1815 * RESULTS
1816 * Success: TRUE
1817 * Failure: FALSE
1820 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1822 LONG lres;
1824 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1825 lres = copy_servername_from_name(pName, NULL);
1826 if (lres) {
1827 FIXME("server %s not supported\n", debugstr_w(pName));
1828 SetLastError(ERROR_ACCESS_DENIED);
1829 return FALSE;
1832 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1833 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1836 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1839 /******************************************************************************
1840 * fpClosePrinter [exported through PRINTPROVIDOR]
1842 * Close a printer handle and free associated resources
1844 * PARAMS
1845 * hPrinter [I] Printerhandle to close
1847 * RESULTS
1848 * Success: TRUE
1849 * Failure: FALSE
1852 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1854 printer_t *printer = (printer_t *) hPrinter;
1856 TRACE("(%p)\n", hPrinter);
1858 if (printer) {
1859 printer_free(printer);
1860 return TRUE;
1862 return FALSE;
1865 static BOOL wrap_ConfigurePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
1867 if (pm->monitor.pfnConfigurePort)
1868 return pm->monitor.pfnConfigurePort(pm->hmon, name, hwnd, port_name);
1870 if (pm->old_ConfigurePort)
1871 return pm->old_ConfigurePort(name, hwnd, port_name);
1873 WARN("ConfigurePort is not implemented by monitor\n");
1874 return FALSE;
1877 /******************************************************************************
1878 * fpConfigurePort [exported through PRINTPROVIDOR]
1880 * Display the Configuration-Dialog for a specific Port
1882 * PARAMS
1883 * pName [I] Servername or NULL (local Computer)
1884 * hWnd [I] Handle to parent Window for the Dialog-Box
1885 * pPortName [I] Name of the Port, that should be configured
1887 * RETURNS
1888 * Success: TRUE
1889 * Failure: FALSE
1892 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1894 monitor_t * pm;
1895 monitor_t * pui;
1896 LONG lres;
1897 DWORD res;
1899 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1901 lres = copy_servername_from_name(pName, NULL);
1902 if (lres) {
1903 FIXME("server %s not supported\n", debugstr_w(pName));
1904 SetLastError(ERROR_INVALID_NAME);
1905 return FALSE;
1908 /* an empty Portname is Invalid, but can popup a Dialog */
1909 if (!pPortName[0]) {
1910 SetLastError(ERROR_NOT_SUPPORTED);
1911 return FALSE;
1914 pm = monitor_load_by_port(pPortName);
1915 if (pm && (pm->monitor.pfnConfigurePort || pm->old_ConfigurePort))
1917 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1918 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1919 res = wrap_ConfigurePort(pm, pName, hWnd, pPortName);
1920 TRACE("got %d with %u\n", res, GetLastError());
1922 else
1924 pui = monitor_loadui(pm);
1925 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1926 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1927 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1928 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1929 TRACE("got %d with %u\n", res, GetLastError());
1931 else
1933 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1934 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1935 pui, debugstr_w(pui ? pui->dllname : NULL));
1937 SetLastError(ERROR_NOT_SUPPORTED);
1938 res = FALSE;
1940 monitor_unload(pui);
1942 monitor_unload(pm);
1944 TRACE("returning %d with %u\n", res, GetLastError());
1945 return res;
1948 /******************************************************************
1949 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1951 * Delete a specific Printmonitor from a Printing-Environment
1953 * PARAMS
1954 * pName [I] Servername or NULL (local Computer)
1955 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1956 * pMonitorName [I] Name of the Monitor, that should be deleted
1958 * RETURNS
1959 * Success: TRUE
1960 * Failure: FALSE
1962 * NOTES
1963 * pEnvironment is ignored in Windows for the local Computer.
1967 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1969 monitor_t *pm;
1970 HKEY hroot = NULL;
1971 LONG lres;
1973 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1974 debugstr_w(pMonitorName));
1976 lres = copy_servername_from_name(pName, NULL);
1977 if (lres) {
1978 FIXME("server %s not supported\n", debugstr_w(pName));
1979 SetLastError(ERROR_INVALID_NAME);
1980 return FALSE;
1983 /* pEnvironment is ignored in Windows for the local Computer */
1984 if (!pMonitorName || !pMonitorName[0]) {
1985 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1986 SetLastError(ERROR_INVALID_PARAMETER);
1987 return FALSE;
1990 /* Unload the monitor if it's loaded */
1991 EnterCriticalSection(&monitor_handles_cs);
1992 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1994 if (pm->name && !lstrcmpW(pMonitorName, pm->name))
1996 monitor_unload(pm);
1997 break;
2000 LeaveCriticalSection(&monitor_handles_cs);
2002 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2003 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2004 return FALSE;
2007 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2008 TRACE("%s deleted\n", debugstr_w(pMonitorName));
2009 RegCloseKey(hroot);
2010 return TRUE;
2013 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
2014 RegCloseKey(hroot);
2016 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2017 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2018 return FALSE;
2021 static BOOL wrap_DeletePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
2023 if (pm->monitor.pfnDeletePort)
2024 return pm->monitor.pfnDeletePort(pm->hmon, name, hwnd, port_name);
2026 if (pm->old_ConfigurePort)
2027 return pm->old_DeletePort(name, hwnd, port_name);
2029 WARN("DeletePort is not implemented by monitor\n");
2030 return FALSE;
2033 /*****************************************************************************
2034 * fpDeletePort [exported through PRINTPROVIDOR]
2036 * Delete a specific Port
2038 * PARAMS
2039 * pName [I] Servername or NULL (local Computer)
2040 * hWnd [I] Handle to parent Window for the Dialog-Box
2041 * pPortName [I] Name of the Port, that should be deleted
2043 * RETURNS
2044 * Success: TRUE
2045 * Failure: FALSE
2048 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2050 monitor_t * pm;
2051 monitor_t * pui;
2052 LONG lres;
2053 DWORD res;
2055 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2057 lres = copy_servername_from_name(pName, NULL);
2058 if (lres) {
2059 FIXME("server %s not supported\n", debugstr_w(pName));
2060 SetLastError(ERROR_INVALID_NAME);
2061 return FALSE;
2064 /* an empty Portname is Invalid */
2065 if (!pPortName[0]) {
2066 SetLastError(ERROR_NOT_SUPPORTED);
2067 return FALSE;
2070 pm = monitor_load_by_port(pPortName);
2071 if (pm && (pm->monitor.pfnDeletePort || pm->old_DeletePort))
2073 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2074 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2075 res = wrap_DeletePort(pm, pName, hWnd, pPortName);
2076 TRACE("got %d with %u\n", res, GetLastError());
2078 else
2080 pui = monitor_loadui(pm);
2081 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2082 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2083 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2084 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2085 TRACE("got %d with %u\n", res, GetLastError());
2087 else
2089 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2090 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2091 pui, debugstr_w(pui ? pui->dllname : NULL));
2093 SetLastError(ERROR_NOT_SUPPORTED);
2094 res = FALSE;
2096 monitor_unload(pui);
2098 monitor_unload(pm);
2100 TRACE("returning %d with %u\n", res, GetLastError());
2101 return res;
2104 /*****************************************************************************
2105 * fpEnumMonitors [exported through PRINTPROVIDOR]
2107 * Enumerate available Port-Monitors
2109 * PARAMS
2110 * pName [I] Servername or NULL (local Computer)
2111 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2112 * pMonitors [O] PTR to Buffer that receives the Result
2113 * cbBuf [I] Size of Buffer at pMonitors
2114 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2115 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2117 * RETURNS
2118 * Success: TRUE
2119 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2121 * NOTES
2122 * Windows reads the Registry once and cache the Results.
2125 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
2126 LPDWORD pcbNeeded, LPDWORD pcReturned)
2128 DWORD numentries = 0;
2129 DWORD needed = 0;
2130 LONG lres;
2131 BOOL res = FALSE;
2133 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
2134 cbBuf, pcbNeeded, pcReturned);
2136 lres = copy_servername_from_name(pName, NULL);
2137 if (lres) {
2138 FIXME("server %s not supported\n", debugstr_w(pName));
2139 SetLastError(ERROR_INVALID_NAME);
2140 goto em_cleanup;
2143 if (!Level || (Level > 2)) {
2144 WARN("level (%d) is ignored in win9x\n", Level);
2145 SetLastError(ERROR_INVALID_LEVEL);
2146 return FALSE;
2149 /* Scan all Monitor-Keys */
2150 numentries = 0;
2151 needed = get_local_monitors(Level, NULL, 0, &numentries);
2153 /* we calculated the needed buffersize. now do more error-checks */
2154 if (cbBuf < needed) {
2155 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2156 goto em_cleanup;
2159 /* fill the Buffer with the Monitor-Keys */
2160 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2161 res = TRUE;
2163 em_cleanup:
2164 if (pcbNeeded) *pcbNeeded = needed;
2165 if (pcReturned) *pcReturned = numentries;
2167 TRACE("returning %d with %d (%d byte for %d entries)\n",
2168 res, GetLastError(), needed, numentries);
2170 return (res);
2173 /******************************************************************************
2174 * fpEnumPorts [exported through PRINTPROVIDOR]
2176 * Enumerate available Ports
2178 * PARAMS
2179 * pName [I] Servername or NULL (local Computer)
2180 * Level [I] Structure-Level (1 or 2)
2181 * pPorts [O] PTR to Buffer that receives the Result
2182 * cbBuf [I] Size of Buffer at pPorts
2183 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2184 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2186 * RETURNS
2187 * Success: TRUE
2188 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2191 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2192 LPDWORD pcbNeeded, LPDWORD pcReturned)
2194 DWORD needed = 0;
2195 DWORD numentries = 0;
2196 LONG lres;
2197 BOOL res = FALSE;
2199 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2200 cbBuf, pcbNeeded, pcReturned);
2202 lres = copy_servername_from_name(pName, NULL);
2203 if (lres) {
2204 FIXME("server %s not supported\n", debugstr_w(pName));
2205 SetLastError(ERROR_INVALID_NAME);
2206 goto emP_cleanup;
2209 if (!Level || (Level > 2)) {
2210 SetLastError(ERROR_INVALID_LEVEL);
2211 goto emP_cleanup;
2214 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2215 SetLastError(RPC_X_NULL_REF_POINTER);
2216 goto emP_cleanup;
2219 EnterCriticalSection(&monitor_handles_cs);
2220 monitor_loadall();
2222 /* Scan all local Ports */
2223 numentries = 0;
2224 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2226 /* we calculated the needed buffersize. now do the error-checks */
2227 if (cbBuf < needed) {
2228 monitor_unloadall();
2229 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2230 goto emP_cleanup_cs;
2232 else if (!pPorts || !pcReturned) {
2233 monitor_unloadall();
2234 SetLastError(RPC_X_NULL_REF_POINTER);
2235 goto emP_cleanup_cs;
2238 /* Fill the Buffer */
2239 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2240 res = TRUE;
2241 monitor_unloadall();
2243 emP_cleanup_cs:
2244 LeaveCriticalSection(&monitor_handles_cs);
2246 emP_cleanup:
2247 if (pcbNeeded) *pcbNeeded = needed;
2248 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2250 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2251 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2253 return (res);
2256 /*****************************************************************************
2257 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2259 * Enumerate available Print Processors
2261 * PARAMS
2262 * pName [I] Servername or NULL (local Computer)
2263 * pEnvironment [I] Printing-Environment or NULL (Default)
2264 * Level [I] Structure-Level (Only 1 is allowed)
2265 * pPPInfo [O] PTR to Buffer that receives the Result
2266 * cbBuf [I] Size of Buffer at pMonitors
2267 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2268 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2270 * RETURNS
2271 * Success: TRUE
2272 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2275 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2276 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2278 const printenv_t * env;
2279 LPWSTR regpathW = NULL;
2280 DWORD numentries = 0;
2281 DWORD needed = 0;
2282 LONG lres;
2283 BOOL res = FALSE;
2285 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2286 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2288 lres = copy_servername_from_name(pName, NULL);
2289 if (lres) {
2290 FIXME("server %s not supported\n", debugstr_w(pName));
2291 SetLastError(ERROR_INVALID_NAME);
2292 goto epp_cleanup;
2295 if (Level != 1) {
2296 SetLastError(ERROR_INVALID_LEVEL);
2297 goto epp_cleanup;
2300 env = validate_envW(pEnvironment);
2301 if (!env)
2302 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2304 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2305 (lstrlenW(env->envname) * sizeof(WCHAR)));
2307 if (!regpathW)
2308 goto epp_cleanup;
2310 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2312 /* Scan all Printprocessor-Keys */
2313 numentries = 0;
2314 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2316 /* we calculated the needed buffersize. now do more error-checks */
2317 if (cbBuf < needed) {
2318 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2319 goto epp_cleanup;
2322 /* fill the Buffer with the Printprocessor Infos */
2323 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2324 res = TRUE;
2326 epp_cleanup:
2327 heap_free(regpathW);
2328 if (pcbNeeded) *pcbNeeded = needed;
2329 if (pcReturned) *pcReturned = numentries;
2331 TRACE("returning %d with %d (%d byte for %d entries)\n",
2332 res, GetLastError(), needed, numentries);
2334 return (res);
2337 /******************************************************************************
2338 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2340 * Return the PATH for the Print-Processors
2342 * PARAMS
2343 * pName [I] Servername or NULL (this computer)
2344 * pEnvironment [I] Printing-Environment or NULL (Default)
2345 * level [I] Structure-Level (must be 1)
2346 * pPPInfo [O] PTR to Buffer that receives the Result
2347 * cbBuf [I] Size of Buffer at pPPInfo
2348 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2350 * RETURNS
2351 * Success: TRUE
2352 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2354 * Native Values returned in pPPInfo on Success for this computer:
2355 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2356 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2357 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2359 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2362 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2363 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2365 const printenv_t * env;
2366 DWORD needed;
2367 LONG lres;
2369 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2370 level, pPPInfo, cbBuf, pcbNeeded);
2372 *pcbNeeded = 0;
2373 lres = copy_servername_from_name(pName, NULL);
2374 if (lres) {
2375 FIXME("server %s not supported\n", debugstr_w(pName));
2376 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2377 return FALSE;
2380 env = validate_envW(pEnvironment);
2381 if (!env)
2382 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2384 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2385 needed = GetSystemDirectoryW(NULL, 0);
2386 /* add the Size for the Subdirectories */
2387 needed += lstrlenW(L"\\spool\\prtprocs\\");
2388 needed += lstrlenW(env->subdir);
2389 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2391 *pcbNeeded = needed;
2393 if (needed > cbBuf) {
2394 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2395 return FALSE;
2398 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2399 /* add the Subdirectories */
2400 lstrcatW((LPWSTR) pPPInfo, L"\\spool\\prtprocs\\");
2401 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2402 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2403 return TRUE;
2406 /******************************************************************************
2407 * fpOpenPrinter [exported through PRINTPROVIDOR]
2409 * Open a Printer / Printserver or a Printer-Object
2411 * PARAMS
2412 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2413 * pPrinter [O] The resulting Handle is stored here
2414 * pDefaults [I] PTR to Default Printer Settings or NULL
2416 * RETURNS
2417 * Success: TRUE
2418 * Failure: FALSE
2420 * NOTES
2421 * lpPrinterName is one of:
2422 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2423 *| Printer: "PrinterName"
2424 *| Printer-Object: "PrinterName,Job xxx"
2425 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2426 *| XcvPort: "Servername,XcvPort PortName"
2430 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2431 LPPRINTER_DEFAULTSW pDefaults)
2434 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2436 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2438 return (*pPrinter != 0);
2441 /******************************************************************************
2442 * fpXcvData [exported through PRINTPROVIDOR]
2444 * Execute commands in the Printmonitor DLL
2446 * PARAMS
2447 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2448 * pszDataName [i] Name of the command to execute
2449 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2450 * cbInputData [i] Size in Bytes of Buffer at pInputData
2451 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2452 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2453 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2454 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2456 * RETURNS
2457 * Success: TRUE
2458 * Failure: FALSE
2460 * NOTES
2461 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2462 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2464 * Minimal List of commands, that a Printmonitor DLL should support:
2466 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2467 *| "AddPort" : Add a Port
2468 *| "DeletePort": Delete a Port
2470 * Many Printmonitors support additional commands. Examples for localspl.dll:
2471 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2472 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2475 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2476 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2477 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2479 printer_t *printer = (printer_t * ) hXcv;
2481 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2482 pInputData, cbInputData, pOutputData,
2483 cbOutputData, pcbOutputNeeded, pdwStatus);
2485 if (!printer || (!printer->hXcv)) {
2486 SetLastError(ERROR_INVALID_HANDLE);
2487 return FALSE;
2490 if (!pcbOutputNeeded) {
2491 SetLastError(ERROR_INVALID_PARAMETER);
2492 return FALSE;
2495 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2496 SetLastError(RPC_X_NULL_REF_POINTER);
2497 return FALSE;
2500 *pcbOutputNeeded = 0;
2502 if (printer->pm->monitor.pfnXcvDataPort)
2503 *pdwStatus = printer->pm->monitor.pfnXcvDataPort(printer->hXcv, pszDataName,
2504 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2506 return TRUE;
2509 static const PRINTPROVIDOR backend = {
2510 fpOpenPrinter,
2511 NULL, /* fpSetJob */
2512 NULL, /* fpGetJob */
2513 NULL, /* fpEnumJobs */
2514 NULL, /* fpAddPrinter */
2515 NULL, /* fpDeletePrinter */
2516 NULL, /* fpSetPrinter */
2517 NULL, /* fpGetPrinter */
2518 NULL, /* fpEnumPrinters */
2519 NULL, /* fpAddPrinterDriver */
2520 NULL, /* fpEnumPrinterDrivers */
2521 NULL, /* fpGetPrinterDriver */
2522 fpGetPrinterDriverDirectory,
2523 NULL, /* fpDeletePrinterDriver */
2524 NULL, /* fpAddPrintProcessor */
2525 fpEnumPrintProcessors,
2526 fpGetPrintProcessorDirectory,
2527 NULL, /* fpDeletePrintProcessor */
2528 NULL, /* fpEnumPrintProcessorDatatypes */
2529 NULL, /* fpStartDocPrinter */
2530 NULL, /* fpStartPagePrinter */
2531 NULL, /* fpWritePrinter */
2532 NULL, /* fpEndPagePrinter */
2533 NULL, /* fpAbortPrinter */
2534 NULL, /* fpReadPrinter */
2535 NULL, /* fpEndDocPrinter */
2536 NULL, /* fpAddJob */
2537 NULL, /* fpScheduleJob */
2538 NULL, /* fpGetPrinterData */
2539 NULL, /* fpSetPrinterData */
2540 NULL, /* fpWaitForPrinterChange */
2541 fpClosePrinter,
2542 NULL, /* fpAddForm */
2543 NULL, /* fpDeleteForm */
2544 NULL, /* fpGetForm */
2545 NULL, /* fpSetForm */
2546 NULL, /* fpEnumForms */
2547 fpEnumMonitors,
2548 fpEnumPorts,
2549 fpAddPort,
2550 fpConfigurePort,
2551 fpDeletePort,
2552 NULL, /* fpCreatePrinterIC */
2553 NULL, /* fpPlayGdiScriptOnPrinterIC */
2554 NULL, /* fpDeletePrinterIC */
2555 NULL, /* fpAddPrinterConnection */
2556 NULL, /* fpDeletePrinterConnection */
2557 NULL, /* fpPrinterMessageBox */
2558 fpAddMonitor,
2559 fpDeleteMonitor,
2560 NULL, /* fpResetPrinter */
2561 NULL, /* fpGetPrinterDriverEx */
2562 NULL, /* fpFindFirstPrinterChangeNotification */
2563 NULL, /* fpFindClosePrinterChangeNotification */
2564 fpAddPortEx,
2565 NULL, /* fpShutDown */
2566 NULL, /* fpRefreshPrinterChangeNotification */
2567 NULL, /* fpOpenPrinterEx */
2568 NULL, /* fpAddPrinterEx */
2569 NULL, /* fpSetPort */
2570 NULL, /* fpEnumPrinterData */
2571 NULL, /* fpDeletePrinterData */
2572 NULL, /* fpClusterSplOpen */
2573 NULL, /* fpClusterSplClose */
2574 NULL, /* fpClusterSplIsAlive */
2575 NULL, /* fpSetPrinterDataEx */
2576 NULL, /* fpGetPrinterDataEx */
2577 NULL, /* fpEnumPrinterDataEx */
2578 NULL, /* fpEnumPrinterKey */
2579 NULL, /* fpDeletePrinterDataEx */
2580 NULL, /* fpDeletePrinterKey */
2581 NULL, /* fpSeekPrinter */
2582 NULL, /* fpDeletePrinterDriverEx */
2583 NULL, /* fpAddPerMachineConnection */
2584 NULL, /* fpDeletePerMachineConnection */
2585 NULL, /* fpEnumPerMachineConnections */
2586 fpXcvData,
2587 fpAddPrinterDriverEx,
2588 NULL, /* fpSplReadPrinter */
2589 NULL, /* fpDriverUnloadComplete */
2590 NULL, /* fpGetSpoolFileInfo */
2591 NULL, /* fpCommitSpoolData */
2592 NULL, /* fpCloseSpoolFileHandle */
2593 NULL, /* fpFlushPrinter */
2594 NULL, /* fpSendRecvBidiData */
2595 NULL /* fpAddDriverCatalog */
2598 /*****************************************************
2599 * InitializePrintProvidor (localspl.@)
2601 * Initialize the Printprovider
2603 * PARAMS
2604 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2605 * cbPrintProvidor [I] Size of Buffer in Bytes
2606 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2608 * RETURNS
2609 * Success: TRUE and pPrintProvidor filled
2610 * Failure: FALSE
2612 * NOTES
2613 * The RegistryPath should be:
2614 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2615 * but this Parameter is ignored in "localspl.dll".
2619 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2620 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2623 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2624 memcpy(pPrintProvidor, &backend,
2625 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2627 return TRUE;