ole32: Fix a spelling error in a function parameter name.
[wine.git] / dlls / localspl / provider.c
blob326313d8f0c48d05eb1747f119191b09f5916cba
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 PRINTPROVIDOR * pprovider = NULL;
104 static const WCHAR backslashW[] = {'\\',0};
105 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
106 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
107 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
108 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
109 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
110 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
111 static const WCHAR emptyW[] = {0};
112 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
113 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
114 'c','o','n','t','r','o','l','\\',
115 'P','r','i','n','t','\\',
116 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
117 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
118 static const WCHAR fmt_printprocessorsW[] = { 'S','y','s','t','e','m','\\',
119 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120 'C','o','n','t','r','o','l','\\',
121 'P','r','i','n','t','\\',
122 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
123 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
124 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
125 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
126 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
127 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
128 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
129 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s','\\',0};
134 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
135 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
136 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
141 static const WCHAR spoolW[] = {'\\','s','p','o','o','l',0};
142 static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
143 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
144 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
145 static const WCHAR version0_subdirW[] = {'\\','0',0};
146 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
147 static const WCHAR version3_subdirW[] = {'\\','3',0};
148 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
149 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
150 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
151 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'P','o','r','t','s',0};
156 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
157 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
158 static const WCHAR x64_subdirW[] = {'x','6','4',0};
159 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
160 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
161 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
162 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
165 static const printenv_t env_ia64 = {ia64_envnameW, ia64_subdirW, 3,
166 version3_regpathW, version3_subdirW};
168 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
169 version3_regpathW, version3_subdirW};
171 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
172 version3_regpathW, version3_subdirW};
174 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
175 version0_regpathW, version0_subdirW};
177 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
180 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
181 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
182 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
183 0, sizeof(DRIVER_INFO_8W)};
186 /******************************************************************
187 * strdupW [internal]
189 * create a copy of a unicode-string
192 static LPWSTR strdupW(LPCWSTR p)
194 LPWSTR ret;
195 DWORD len;
197 if(!p) return NULL;
198 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
199 ret = heap_alloc(len);
200 if (ret) memcpy(ret, p, len);
201 return ret;
204 /******************************************************************
205 * apd_copyfile [internal]
207 * Copy a file from the driverdirectory to the versioned directory
209 * RETURNS
210 * Success: TRUE
211 * Failure: FALSE
214 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
216 WCHAR *srcname;
217 BOOL res;
219 apd->src[apd->srclen] = '\0';
220 apd->dst[apd->dstlen] = '\0';
222 if (!pathname || !pathname[0]) {
223 /* nothing to copy */
224 return TRUE;
227 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
228 srcname = pathname;
229 else
231 srcname = apd->src;
232 lstrcatW( srcname, file_part );
234 lstrcatW( apd->dst, file_part );
236 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
238 /* FIXME: handle APD_COPY_NEW_FILES */
239 res = CopyFileW(srcname, apd->dst, FALSE);
240 TRACE("got %d with %u\n", res, GetLastError());
242 return apd->lazy || res;
245 /******************************************************************
246 * copy_servername_from_name (internal)
248 * for an external server, the serverpart from the name is copied.
250 * RETURNS
251 * the length (in WCHAR) of the serverpart (0 for the local computer)
252 * (-length), when the name is too long
255 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
257 LPCWSTR server;
258 LPWSTR ptr;
259 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
260 DWORD len;
261 DWORD serverlen;
263 if (target) *target = '\0';
265 if (name == NULL) return 0;
266 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
268 server = &name[2];
269 /* skip over both backslash, find separator '\' */
270 ptr = wcschr(server, '\\');
271 serverlen = (ptr) ? ptr - server : lstrlenW(server);
273 /* servername is empty */
274 if (serverlen == 0) return 0;
276 TRACE("found %s\n", debugstr_wn(server, serverlen));
278 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
280 if (target) {
281 memcpy(target, server, serverlen * sizeof(WCHAR));
282 target[serverlen] = '\0';
285 len = ARRAY_SIZE(buffer);
286 if (GetComputerNameW(buffer, &len)) {
287 if ((serverlen == len) && (wcsnicmp(server, buffer, len) == 0)) {
288 /* The requested Servername is our computername */
289 return 0;
292 return serverlen;
295 /******************************************************************
296 * get_basename_from_name (internal)
298 * skip over the serverpart from the full name
301 static LPCWSTR get_basename_from_name(LPCWSTR name)
303 if (name == NULL) return NULL;
304 if ((name[0] == '\\') && (name[1] == '\\')) {
305 /* skip over the servername and search for the following '\' */
306 name = wcschr(&name[2], '\\');
307 if ((name) && (name[1])) {
308 /* found a separator ('\') followed by a name:
309 skip over the separator and return the rest */
310 name++;
312 else
314 /* no basename present (we found only a servername) */
315 return NULL;
318 return name;
321 /******************************************************************
322 * monitor_unload [internal]
324 * release a printmonitor and unload it from memory, when needed
327 static void monitor_unload(monitor_t * pm)
329 if (pm == NULL) return;
330 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
332 EnterCriticalSection(&monitor_handles_cs);
334 if (pm->refcount) pm->refcount--;
336 if (pm->refcount == 0) {
337 list_remove(&pm->entry);
339 if (pm->monitor.pfnShutdown)
340 pm->monitor.pfnShutdown(pm->hmon);
342 FreeLibrary(pm->hdll);
343 heap_free(pm->name);
344 heap_free(pm->dllname);
345 heap_free(pm);
347 LeaveCriticalSection(&monitor_handles_cs);
350 /******************************************************************
351 * monitor_unloadall [internal]
353 * release all registered printmonitors and unload them from memory, when needed
357 static void monitor_unloadall(void)
359 monitor_t * pm;
360 monitor_t * next;
362 EnterCriticalSection(&monitor_handles_cs);
363 /* iterate through the list, with safety against removal */
364 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
366 /* skip monitorui dlls */
367 if (pm->monitor.cbSize) monitor_unload(pm);
369 LeaveCriticalSection(&monitor_handles_cs);
372 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
373 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
374 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
376 FIXME("stub\n");
377 return ERROR_CALL_NOT_IMPLEMENTED;
380 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
381 PHANDLE phkResult, HANDLE hSpooler)
383 FIXME("stub\n");
384 return ERROR_CALL_NOT_IMPLEMENTED;
387 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
389 FIXME("stub\n");
390 return ERROR_CALL_NOT_IMPLEMENTED;
393 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
395 FIXME("stub\n");
396 return ERROR_CALL_NOT_IMPLEMENTED;
399 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
400 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
402 FIXME("stub\n");
403 return ERROR_CALL_NOT_IMPLEMENTED;
406 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
407 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
408 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
409 HANDLE hSpooler)
411 FIXME("stub\n");
412 return ERROR_CALL_NOT_IMPLEMENTED;
415 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
416 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
418 FIXME("stub\n");
419 return ERROR_CALL_NOT_IMPLEMENTED;
422 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
424 FIXME("stub\n");
425 return ERROR_CALL_NOT_IMPLEMENTED;
428 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
429 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
430 HANDLE hSpooler)
432 FIXME("stub\n");
433 return ERROR_CALL_NOT_IMPLEMENTED;
436 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
437 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
439 FIXME("stub\n");
440 return ERROR_CALL_NOT_IMPLEMENTED;
443 static MONITORREG monreg =
445 sizeof(MONITORREG),
446 CreateKey,
447 OpenKey,
448 CloseKey,
449 DeleteKey,
450 EnumKey,
451 QueryInfoKey,
452 SetValue,
453 DeleteValue,
454 EnumValue,
455 QueryValue
458 /******************************************************************
459 * monitor_load [internal]
461 * load a printmonitor, get the dllname from the registry, when needed
462 * initialize the monitor and dump found function-pointers
464 * On failure, SetLastError() is called and NULL is returned
467 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
469 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
470 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
471 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
472 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
473 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
475 monitor_t * pm = NULL;
476 monitor_t * cursor;
477 LPWSTR regroot = NULL;
478 LPWSTR driver = dllname;
479 HKEY hroot = 0;
481 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
482 /* Is the Monitor already loaded? */
483 EnterCriticalSection(&monitor_handles_cs);
485 if (name) {
486 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
488 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
489 pm = cursor;
490 break;
495 if (pm == NULL) {
496 pm = heap_alloc_zero(sizeof(monitor_t));
497 if (pm == NULL) goto cleanup;
498 list_add_tail(&monitor_handles, &pm->entry);
500 pm->refcount++;
502 if (pm->name == NULL) {
503 /* Load the monitor */
504 DWORD len;
506 if (name) {
507 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
508 regroot = heap_alloc(len * sizeof(WCHAR));
511 if (regroot) {
512 lstrcpyW(regroot, monitorsW);
513 lstrcatW(regroot, name);
514 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
515 /* Get the Driver from the Registry */
516 if (driver == NULL) {
517 DWORD namesize;
518 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
519 &namesize) == ERROR_SUCCESS) {
520 driver = heap_alloc(namesize);
521 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
525 else
526 WARN("%s not found\n", debugstr_w(regroot));
529 pm->name = strdupW(name);
530 pm->dllname = strdupW(driver);
532 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
533 monitor_unload(pm);
534 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
535 pm = NULL;
536 goto cleanup;
539 pm->hdll = LoadLibraryW(driver);
540 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
542 if (pm->hdll == NULL) {
543 monitor_unload(pm);
544 SetLastError(ERROR_MOD_NOT_FOUND);
545 pm = NULL;
546 goto cleanup;
549 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
550 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
551 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
552 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
553 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
556 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
557 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
558 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
559 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
560 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
562 if (pInitializePrintMonitorUI != NULL) {
563 pm->monitorUI = pInitializePrintMonitorUI();
564 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
565 if (pm->monitorUI) {
566 TRACE("0x%08x: dwMonitorSize (%d)\n",
567 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
572 if (pInitializePrintMonitor2 && hroot) {
573 MONITORINIT init;
574 MONITOR2 *monitor2;
575 HANDLE hmon;
577 memset(&init, 0, sizeof(init));
578 init.cbSize = sizeof(init);
579 init.hckRegistryRoot = hroot;
580 init.pMonitorReg = &monreg;
581 init.bLocal = TRUE;
583 monitor2 = pInitializePrintMonitor2(&init, &hmon);
584 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
585 monitor2, debugstr_w(driver), debugstr_w(regroot));
586 if (monitor2)
588 memcpy(&pm->monitor, monitor2, min(monitor2->cbSize, sizeof(pm->monitor)));
589 pm->hmon = hmon;
592 else if (pInitializePrintMonitor && regroot) {
593 MONITOREX *pmonitorEx;
595 pmonitorEx = pInitializePrintMonitor(regroot);
596 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
597 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
598 if (pmonitorEx)
600 /* Layout of MONITOREX and MONITOR2 mostly matches */
601 memcpy(&pm->monitor, pmonitorEx, min(pmonitorEx->dwMonitorSize + sizeof(void *), sizeof(pm->monitor)));
602 /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */
603 pm->monitor.cbSize += sizeof(void *);
605 pm->old_EnumPorts = pmonitorEx->Monitor.pfnEnumPorts;
606 pm->old_OpenPort = pmonitorEx->Monitor.pfnOpenPort;
607 pm->old_OpenPortEx = pmonitorEx->Monitor.pfnOpenPortEx;
608 pm->old_AddPort = pmonitorEx->Monitor.pfnAddPort;
609 pm->old_AddPortEx = pmonitorEx->Monitor.pfnAddPortEx;
610 pm->old_ConfigurePort = pmonitorEx->Monitor.pfnConfigurePort;
611 pm->old_DeletePort = pmonitorEx->Monitor.pfnDeletePort;
612 pm->old_XcvOpenPort = pmonitorEx->Monitor.pfnXcvOpenPort;
614 pm->monitor.pfnEnumPorts = NULL;
615 pm->monitor.pfnOpenPort = NULL;
616 pm->monitor.pfnOpenPortEx = NULL;
617 pm->monitor.pfnAddPort = NULL;
618 pm->monitor.pfnAddPortEx = NULL;
619 pm->monitor.pfnConfigurePort = NULL;
620 pm->monitor.pfnDeletePort = NULL;
621 pm->monitor.pfnXcvOpenPort = NULL;
625 if (!pm->monitor.cbSize && regroot) {
626 if (pInitializeMonitorEx != NULL) {
627 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
629 if (pInitializeMonitor != NULL) {
630 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
633 if (!pm->monitor.cbSize && !pm->monitorUI) {
634 monitor_unload(pm);
635 SetLastError(ERROR_PROC_NOT_FOUND);
636 pm = NULL;
639 cleanup:
640 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
641 pm->refcount++;
642 pm_localport = pm;
644 LeaveCriticalSection(&monitor_handles_cs);
645 if (driver != dllname) heap_free(driver);
646 if (hroot) RegCloseKey(hroot);
647 heap_free(regroot);
648 TRACE("=> %p\n", pm);
649 return pm;
652 /******************************************************************
653 * monitor_loadall [internal]
655 * Load all registered monitors
658 static DWORD monitor_loadall(void)
660 monitor_t * pm;
661 DWORD registered = 0;
662 DWORD loaded = 0;
663 HKEY hmonitors;
664 WCHAR buffer[MAX_PATH];
665 DWORD id = 0;
667 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
668 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
669 NULL, NULL, NULL, NULL, NULL);
671 TRACE("%d monitors registered\n", registered);
673 while (id < registered) {
674 buffer[0] = '\0';
675 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
676 pm = monitor_load(buffer, NULL);
677 if (pm) loaded++;
678 id++;
680 RegCloseKey(hmonitors);
682 TRACE("%d monitors loaded\n", loaded);
683 return loaded;
686 /******************************************************************
687 * monitor_loadui [internal]
689 * load the userinterface-dll for a given portmonitor
691 * On failure, NULL is returned
693 static monitor_t * monitor_loadui(monitor_t * pm)
695 monitor_t * pui = NULL;
696 WCHAR buffer[MAX_PATH];
697 HANDLE hXcv;
698 DWORD len;
699 DWORD res = 0;
701 if (pm == NULL) return NULL;
702 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
704 /* Try the Portmonitor first; works for many monitors */
705 if (pm->monitorUI) {
706 EnterCriticalSection(&monitor_handles_cs);
707 pm->refcount++;
708 LeaveCriticalSection(&monitor_handles_cs);
709 return pm;
712 /* query the userinterface-dllname from the Portmonitor */
713 /* building (",XcvMonitor %s",pm->name) not needed yet */
714 if (pm->monitor.pfnXcvOpenPort)
715 res = pm->monitor.pfnXcvOpenPort(pm->hmon, emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
716 else if (pm->old_XcvOpenPort)
717 res = pm->old_XcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
718 TRACE("got %u with %p\n", res, hXcv);
719 if (res) {
720 res = pm->monitor.pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
721 TRACE("got %u with %s\n", res, debugstr_w(buffer));
722 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
723 pm->monitor.pfnXcvClosePort(hXcv);
725 return pui;
728 /******************************************************************
729 * monitor_load_by_port [internal]
731 * load a printmonitor for a given port
733 * On failure, NULL is returned
736 static monitor_t * monitor_load_by_port(LPCWSTR portname)
738 HKEY hroot;
739 HKEY hport;
740 LPWSTR buffer;
741 monitor_t * pm = NULL;
742 DWORD registered = 0;
743 DWORD id = 0;
744 DWORD len;
746 TRACE("(%s)\n", debugstr_w(portname));
748 /* Try the Local Monitor first */
749 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
750 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
751 /* found the portname */
752 RegCloseKey(hroot);
753 return monitor_load(localportW, NULL);
755 RegCloseKey(hroot);
758 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
759 buffer = heap_alloc(len * sizeof(WCHAR));
760 if (buffer == NULL) return NULL;
762 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
763 EnterCriticalSection(&monitor_handles_cs);
764 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
766 while ((pm == NULL) && (id < registered)) {
767 buffer[0] = '\0';
768 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
769 TRACE("testing %s\n", debugstr_w(buffer));
770 len = lstrlenW(buffer);
771 lstrcatW(buffer, bs_ports_bsW);
772 lstrcatW(buffer, portname);
773 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
774 RegCloseKey(hport);
775 buffer[len] = '\0'; /* use only the Monitor-Name */
776 pm = monitor_load(buffer, NULL);
778 id++;
780 LeaveCriticalSection(&monitor_handles_cs);
781 RegCloseKey(hroot);
783 heap_free(buffer);
784 return pm;
787 /******************************************************************
788 * Return the number of bytes for an multi_sz string.
789 * The result includes all \0s
790 * (specifically the extra \0, that is needed as multi_sz terminator).
792 static int multi_sz_lenW(const WCHAR *str)
794 const WCHAR *ptr = str;
795 if (!str) return 0;
798 ptr += lstrlenW(ptr) + 1;
799 } while (*ptr);
801 return (ptr - str + 1) * sizeof(WCHAR);
804 /******************************************************************
805 * validate_envW [internal]
807 * validate the user-supplied printing-environment
809 * PARAMS
810 * env [I] PTR to Environment-String or NULL
812 * RETURNS
813 * Success: PTR to printenv_t
814 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
816 * NOTES
817 * An empty string is handled the same way as NULL.
821 static const printenv_t * validate_envW(LPCWSTR env)
823 const printenv_t *result = NULL;
824 unsigned int i;
826 TRACE("(%s)\n", debugstr_w(env));
827 if (env && env[0])
829 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
831 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
833 result = all_printenv[i];
834 break;
837 if (result == NULL) {
838 FIXME("unsupported Environment: %s\n", debugstr_w(env));
839 SetLastError(ERROR_INVALID_ENVIRONMENT);
841 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
843 else
845 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
848 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
849 return result;
852 /*****************************************************************************
853 * enumerate the local monitors (INTERNAL)
855 * returns the needed size (in bytes) for pMonitors
856 * and *lpreturned is set to number of entries returned in pMonitors
858 * Language-Monitors are also installed in the same Registry-Location but
859 * they are filtered in Windows (not returned by EnumMonitors).
860 * We do no filtering to simplify our Code.
863 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
865 HKEY hroot = NULL;
866 HKEY hentry = NULL;
867 LPWSTR ptr;
868 LPMONITOR_INFO_2W mi;
869 WCHAR buffer[MAX_PATH];
870 WCHAR dllname[MAX_PATH];
871 DWORD dllsize;
872 DWORD len;
873 DWORD index = 0;
874 DWORD needed = 0;
875 DWORD numentries;
876 DWORD entrysize;
878 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
880 numentries = *lpreturned; /* this is 0, when we scan the registry */
881 len = entrysize * numentries;
882 ptr = (LPWSTR) &pMonitors[len];
884 numentries = 0;
885 len = ARRAY_SIZE(buffer);
886 buffer[0] = '\0';
888 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
889 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
890 /* Scan all Monitor-Registry-Keys */
891 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
892 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
893 dllsize = sizeof(dllname);
894 dllname[0] = '\0';
896 /* The Monitor must have a Driver-DLL */
897 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
898 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
899 /* We found a valid DLL for this Monitor. */
900 TRACE("using Driver: %s\n", debugstr_w(dllname));
902 RegCloseKey(hentry);
905 /* Windows returns only Port-Monitors here, but to simplify our code,
906 we do no filtering for Language-Monitors */
907 if (dllname[0]) {
908 numentries++;
909 needed += entrysize;
910 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
911 if (level > 1) {
912 /* we install and return only monitors for "Windows NT x86" */
913 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
914 needed += dllsize;
917 /* required size is calculated. Now fill the user-buffer */
918 if (pMonitors && (cbBuf >= needed)){
919 mi = (LPMONITOR_INFO_2W) pMonitors;
920 pMonitors += entrysize;
922 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
923 mi->pName = ptr;
924 lstrcpyW(ptr, buffer); /* Name of the Monitor */
925 ptr += (len+1); /* len is lstrlenW(monitorname) */
926 if (level > 1) {
927 mi->pEnvironment = ptr;
928 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
929 ptr += (lstrlenW(x86_envnameW)+1);
931 mi->pDLLName = ptr;
932 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
933 ptr += (dllsize / sizeof(WCHAR));
937 index++;
938 len = ARRAY_SIZE(buffer);
939 buffer[0] = '\0';
941 RegCloseKey(hroot);
943 *lpreturned = numentries;
944 TRACE("need %d byte for %d entries\n", needed, numentries);
945 return needed;
948 /*****************************************************************************
949 * enumerate the local print processors (INTERNAL)
951 * returns the needed size (in bytes) for pPPInfo
952 * and *lpreturned is set to number of entries returned in pPPInfo
955 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
957 HKEY hroot = NULL;
958 HKEY hentry = NULL;
959 LPWSTR ptr;
960 PPRINTPROCESSOR_INFO_1W ppi;
961 WCHAR buffer[MAX_PATH];
962 WCHAR dllname[MAX_PATH];
963 DWORD dllsize;
964 DWORD len;
965 DWORD index = 0;
966 DWORD needed = 0;
967 DWORD numentries;
969 numentries = *lpreturned; /* this is 0, when we scan the registry */
970 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
971 ptr = (LPWSTR) &pPPInfo[len];
973 numentries = 0;
974 len = ARRAY_SIZE(buffer);
975 buffer[0] = '\0';
977 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
978 /* add "winprint" first */
979 numentries++;
980 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
981 if (pPPInfo && (cbBuf >= needed)){
982 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
983 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
985 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
986 ppi->pName = ptr;
987 lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
988 ptr += ARRAY_SIZE(winprintW);
991 /* Scan all Printprocessor Keys */
992 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
993 (lstrcmpiW(buffer, winprintW) != 0)) {
994 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
995 dllsize = sizeof(dllname);
996 dllname[0] = '\0';
998 /* The Print Processor must have a Driver-DLL */
999 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1000 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
1001 /* We found a valid DLL for this Print Processor */
1002 TRACE("using Driver: %s\n", debugstr_w(dllname));
1004 RegCloseKey(hentry);
1007 if (dllname[0]) {
1008 numentries++;
1009 needed += sizeof(PRINTPROCESSOR_INFO_1W);
1010 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
1012 /* required size is calculated. Now fill the user-buffer */
1013 if (pPPInfo && (cbBuf >= needed)){
1014 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1015 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1017 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
1018 ppi->pName = ptr;
1019 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
1020 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
1023 index++;
1024 len = ARRAY_SIZE(buffer);
1025 buffer[0] = '\0';
1027 RegCloseKey(hroot);
1029 *lpreturned = numentries;
1030 TRACE("need %d byte for %d entries\n", needed, numentries);
1031 return needed;
1034 static BOOL wrap_EnumPorts(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer,
1035 DWORD size, LPDWORD needed, LPDWORD returned)
1037 if (pm->monitor.pfnEnumPorts)
1038 return pm->monitor.pfnEnumPorts(pm->hmon, name, level, buffer, size, needed, returned);
1040 if (pm->old_EnumPorts)
1041 return pm->old_EnumPorts(name, level, buffer, size, needed, returned);
1043 WARN("EnumPorts is not implemented by monitor\n");
1044 return FALSE;
1047 /******************************************************************
1048 * enumerate the local Ports from all loaded monitors (internal)
1050 * returns the needed size (in bytes) for pPorts
1051 * and *lpreturned is set to number of entries returned in pPorts
1054 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1056 monitor_t * pm;
1057 LPWSTR ptr;
1058 LPPORT_INFO_2W cache;
1059 LPPORT_INFO_2W out;
1060 LPBYTE pi_buffer = NULL;
1061 DWORD pi_allocated = 0;
1062 DWORD pi_needed;
1063 DWORD pi_index;
1064 DWORD pi_returned;
1065 DWORD res;
1066 DWORD outindex = 0;
1067 DWORD needed;
1068 DWORD numentries;
1069 DWORD entrysize;
1071 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1072 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1074 numentries = *lpreturned; /* this is 0, when we scan the registry */
1075 needed = entrysize * numentries;
1076 ptr = (LPWSTR) &pPorts[needed];
1078 numentries = 0;
1079 needed = 0;
1081 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1083 if (pm->monitor.pfnEnumPorts || pm->old_EnumPorts) {
1084 pi_needed = 0;
1085 pi_returned = 0;
1086 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1087 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1088 /* Do not use heap_realloc (we do not need the old data in the buffer) */
1089 heap_free(pi_buffer);
1090 pi_buffer = heap_alloc(pi_needed);
1091 pi_allocated = (pi_buffer) ? pi_needed : 0;
1092 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1094 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
1095 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1097 numentries += pi_returned;
1098 needed += pi_needed;
1100 /* fill the output-buffer (pPorts), if we have one */
1101 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1102 pi_index = 0;
1103 while (pi_returned > pi_index) {
1104 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1105 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1106 out->pPortName = ptr;
1107 lstrcpyW(ptr, cache->pPortName);
1108 ptr += (lstrlenW(ptr)+1);
1109 if (level > 1) {
1110 out->pMonitorName = ptr;
1111 lstrcpyW(ptr, cache->pMonitorName);
1112 ptr += (lstrlenW(ptr)+1);
1114 out->pDescription = ptr;
1115 lstrcpyW(ptr, cache->pDescription);
1116 ptr += (lstrlenW(ptr)+1);
1117 out->fPortType = cache->fPortType;
1118 out->Reserved = cache->Reserved;
1120 pi_index++;
1121 outindex++;
1126 /* the temporary portinfo-buffer is no longer needed */
1127 heap_free(pi_buffer);
1129 *lpreturned = numentries;
1130 TRACE("need %d byte for %d entries\n", needed, numentries);
1131 return needed;
1135 /*****************************************************************************
1136 * open_driver_reg [internal]
1138 * opens the registry for the printer drivers depending on the given input
1139 * variable pEnvironment
1141 * RETURNS:
1142 * Success: the opened hkey
1143 * Failure: NULL
1145 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1147 HKEY retval = NULL;
1148 LPWSTR buffer;
1149 const printenv_t * env;
1151 TRACE("(%s)\n", debugstr_w(pEnvironment));
1153 env = validate_envW(pEnvironment);
1154 if (!env) return NULL;
1156 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1157 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1159 if (buffer) {
1160 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1161 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1162 HeapFree(GetProcessHeap(), 0, buffer);
1164 return retval;
1167 /*****************************************************************************
1168 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1170 * Return the PATH for the Printer-Drivers
1172 * PARAMS
1173 * pName [I] Servername (NT only) or NULL (local Computer)
1174 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1175 * Level [I] Structure-Level (must be 1)
1176 * pDriverDirectory [O] PTR to Buffer that receives the Result
1177 * cbBuf [I] Size of Buffer at pDriverDirectory
1178 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1179 * required for pDriverDirectory
1181 * RETURNS
1182 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1183 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1184 * if cbBuf is too small
1186 * Native Values returned in pDriverDirectory on Success:
1187 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1188 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1189 *| win9x(Windows 4.0): "%winsysdir%"
1191 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1194 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1195 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1197 DWORD needed;
1198 const printenv_t * env;
1199 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1201 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1202 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1204 if (pName != NULL && pName[0]) {
1205 FIXME("server %s not supported\n", debugstr_w(pName));
1206 SetLastError(ERROR_INVALID_PARAMETER);
1207 return FALSE;
1210 env = validate_envW(pEnvironment);
1211 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1214 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1215 needed = GetSystemDirectoryW(NULL, 0);
1216 /* add the Size for the Subdirectories */
1217 needed += lstrlenW(spoolW);
1218 needed += lstrlenW(driversW);
1219 needed += lstrlenW(env->subdir);
1220 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1222 *pcbNeeded = needed;
1224 if (needed > cbBuf) {
1225 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1226 return FALSE;
1229 if (dir == NULL) {
1230 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1231 SetLastError(ERROR_INVALID_USER_BUFFER);
1232 return FALSE;
1235 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1236 /* add the Subdirectories */
1237 lstrcatW( dir, spoolW );
1238 CreateDirectoryW( dir, NULL );
1239 lstrcatW( dir, driversW );
1240 CreateDirectoryW( dir, NULL );
1241 lstrcatW( dir, env->subdir );
1242 CreateDirectoryW( dir, NULL );
1244 TRACE( "=> %s\n", debugstr_w( dir ) );
1245 return TRUE;
1248 /******************************************************************
1249 * driver_load [internal]
1251 * load a driver user interface dll
1253 * On failure, NULL is returned
1257 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1259 WCHAR fullname[MAX_PATH];
1260 HMODULE hui;
1261 DWORD len;
1263 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1265 /* build the driverdir */
1266 len = sizeof(fullname) -
1267 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1269 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1270 (LPBYTE) fullname, len, &len)) {
1271 /* Should never fail */
1272 SetLastError(ERROR_BUFFER_OVERFLOW);
1273 return NULL;
1276 lstrcatW(fullname, env->versionsubdir);
1277 lstrcatW(fullname, backslashW);
1278 lstrcatW(fullname, dllname);
1280 hui = LoadLibraryW(fullname);
1281 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1283 return hui;
1286 /******************************************************************
1287 * printer_free
1288 * free the data pointer of an opened printer
1290 static VOID printer_free(printer_t * printer)
1292 if (printer->hXcv)
1294 if (printer->pm->monitor.pfnXcvClosePort)
1295 printer->pm->monitor.pfnXcvClosePort(printer->hXcv);
1298 monitor_unload(printer->pm);
1300 heap_free(printer->printername);
1301 heap_free(printer->name);
1302 heap_free(printer);
1305 /******************************************************************
1306 * printer_alloc_handle
1307 * alloc a printer handle and remember the data pointer in the printer handle table
1310 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1312 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1313 printer_t *printer = NULL;
1314 LPCWSTR printername;
1315 HKEY hkeyPrinters;
1316 HKEY hkeyPrinter;
1317 DWORD len;
1319 if (copy_servername_from_name(name, servername)) {
1320 FIXME("server %s not supported\n", debugstr_w(servername));
1321 SetLastError(ERROR_INVALID_PRINTER_NAME);
1322 return NULL;
1325 printername = get_basename_from_name(name);
1326 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1328 /* an empty printername is invalid */
1329 if (printername && (!printername[0])) {
1330 SetLastError(ERROR_INVALID_PARAMETER);
1331 return NULL;
1334 printer = heap_alloc_zero(sizeof(printer_t));
1335 if (!printer) goto end;
1337 /* clone the base name. This is NULL for the printserver */
1338 printer->printername = strdupW(printername);
1340 /* clone the full name */
1341 printer->name = strdupW(name);
1342 if (name && (!printer->name)) {
1343 printer_free(printer);
1344 printer = NULL;
1346 if (printername) {
1347 len = ARRAY_SIZE(XcvMonitorW) - 1;
1348 if (wcsncmp(printername, XcvMonitorW, len) == 0) {
1349 /* OpenPrinter(",XcvMonitor ", ...) detected */
1350 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1351 printer->pm = monitor_load(&printername[len], NULL);
1352 if (printer->pm == NULL) {
1353 printer_free(printer);
1354 SetLastError(ERROR_UNKNOWN_PORT);
1355 printer = NULL;
1356 goto end;
1359 else
1361 len = ARRAY_SIZE(XcvPortW) - 1;
1362 if (wcsncmp( printername, XcvPortW, len) == 0) {
1363 /* OpenPrinter(",XcvPort ", ...) detected */
1364 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1365 printer->pm = monitor_load_by_port(&printername[len]);
1366 if (printer->pm == NULL) {
1367 printer_free(printer);
1368 SetLastError(ERROR_UNKNOWN_PORT);
1369 printer = NULL;
1370 goto end;
1375 if (printer->pm) {
1376 if (printer->pm->monitor.pfnXcvOpenPort)
1377 printer->pm->monitor.pfnXcvOpenPort(printer->pm->hmon, &printername[len],
1378 pDefault ? pDefault->DesiredAccess : 0,
1379 &printer->hXcv);
1380 else if (printer->pm->old_XcvOpenPort)
1381 printer->pm->old_XcvOpenPort(&printername[len],
1382 pDefault ? pDefault->DesiredAccess : 0,
1383 &printer->hXcv);
1384 if (printer->hXcv == NULL) {
1385 printer_free(printer);
1386 SetLastError(ERROR_INVALID_PARAMETER);
1387 printer = NULL;
1388 goto end;
1391 else
1393 /* Does the Printer exist? */
1394 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1395 ERR("Can't create Printers key\n");
1396 printer_free(printer);
1397 SetLastError(ERROR_INVALID_PRINTER_NAME);
1398 printer = NULL;
1399 goto end;
1401 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1402 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1403 RegCloseKey(hkeyPrinters);
1404 printer_free(printer);
1405 SetLastError(ERROR_INVALID_PRINTER_NAME);
1406 printer = NULL;
1407 goto end;
1409 RegCloseKey(hkeyPrinter);
1410 RegCloseKey(hkeyPrinters);
1413 else
1415 TRACE("using the local printserver\n");
1418 end:
1420 TRACE("==> %p\n", printer);
1421 return (HANDLE)printer;
1424 static inline WCHAR *get_file_part( WCHAR *name )
1426 WCHAR *ptr = wcsrchr( name, '\\' );
1427 if (ptr) return ptr + 1;
1428 return name;
1431 /******************************************************************************
1432 * myAddPrinterDriverEx [internal]
1434 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1435 * and a special mode with lazy error checking.
1438 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1440 const printenv_t *env;
1441 apd_data_t apd;
1442 DRIVER_INFO_8W di;
1443 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1444 HMODULE hui;
1445 WCHAR *file;
1446 HKEY hroot;
1447 HKEY hdrv;
1448 DWORD disposition;
1449 DWORD len;
1450 LONG lres;
1451 BOOL res;
1453 /* we need to set all entries in the Registry, independent from the Level of
1454 DRIVER_INFO, that the caller supplied */
1456 ZeroMemory(&di, sizeof(di));
1457 if (pDriverInfo && (level < ARRAY_SIZE(di_sizeof))) {
1458 memcpy(&di, pDriverInfo, di_sizeof[level]);
1461 /* dump the most used infos */
1462 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1463 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1464 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1465 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1466 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1467 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1468 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1469 /* dump only the first of the additional Files */
1470 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1473 /* check environment */
1474 env = validate_envW(di.pEnvironment);
1475 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1477 /* fill the copy-data / get the driverdir */
1478 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1479 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1480 (LPBYTE) apd.src, len, &len)) {
1481 /* Should never fail */
1482 return FALSE;
1484 memcpy(apd.dst, apd.src, len);
1485 lstrcatW(apd.src, backslashW);
1486 apd.srclen = lstrlenW(apd.src);
1487 lstrcatW(apd.dst, env->versionsubdir);
1488 lstrcatW(apd.dst, backslashW);
1489 apd.dstlen = lstrlenW(apd.dst);
1490 apd.copyflags = dwFileCopyFlags;
1491 apd.lazy = lazy;
1492 CreateDirectoryW(apd.src, NULL);
1493 CreateDirectoryW(apd.dst, NULL);
1495 hroot = open_driver_reg(env->envname);
1496 if (!hroot) {
1497 ERR("Can't create Drivers key\n");
1498 return FALSE;
1501 /* Fill the Registry for the Driver */
1502 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1503 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1504 &hdrv, &disposition)) != ERROR_SUCCESS) {
1506 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1507 RegCloseKey(hroot);
1508 SetLastError(lres);
1509 return FALSE;
1511 RegCloseKey(hroot);
1513 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1514 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1515 sizeof(DWORD));
1517 file = get_file_part( di.pDriverPath );
1518 RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1519 apd_copyfile( di.pDriverPath, file, &apd );
1521 file = get_file_part( di.pDataFile );
1522 RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1523 apd_copyfile( di.pDataFile, file, &apd );
1525 file = get_file_part( di.pConfigFile );
1526 RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1527 apd_copyfile( di.pConfigFile, file, &apd );
1529 /* settings for level 3 */
1530 if (di.pHelpFile)
1532 file = get_file_part( di.pHelpFile );
1533 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1534 apd_copyfile( di.pHelpFile, file, &apd );
1536 else
1537 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1539 if (di.pDependentFiles && *di.pDependentFiles)
1541 WCHAR *reg, *reg_ptr, *in_ptr;
1542 reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1544 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += lstrlenW( in_ptr ) + 1)
1546 file = get_file_part( in_ptr );
1547 len = lstrlenW( file ) + 1;
1548 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1549 reg_ptr += len;
1550 apd_copyfile( in_ptr, file, &apd );
1552 *reg_ptr = 0;
1554 RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1555 HeapFree( GetProcessHeap(), 0, reg );
1557 else
1558 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1560 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1561 if (di.pMonitorName)
1562 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1563 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1564 else
1565 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1567 if (di.pDefaultDataType)
1568 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1569 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1570 else
1571 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1573 /* settings for level 4 */
1574 if (di.pszzPreviousNames)
1575 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1576 multi_sz_lenW(di.pszzPreviousNames));
1577 else
1578 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1580 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1582 RegCloseKey(hdrv);
1583 hui = driver_load(env, di.pConfigFile);
1584 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1585 if (hui && pDrvDriverEvent) {
1587 /* Support for DrvDriverEvent is optional */
1588 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1589 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1590 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1591 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1593 FreeLibrary(hui);
1595 TRACE("=> TRUE with %u\n", GetLastError());
1596 return TRUE;
1600 /******************************************************************************
1601 * fpAddMonitor [exported through PRINTPROVIDOR]
1603 * Install a Printmonitor
1605 * PARAMS
1606 * pName [I] Servername or NULL (local Computer)
1607 * Level [I] Structure-Level (Must be 2)
1608 * pMonitors [I] PTR to MONITOR_INFO_2
1610 * RETURNS
1611 * Success: TRUE
1612 * Failure: FALSE
1614 * NOTES
1615 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1618 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1620 const printenv_t * env;
1621 monitor_t * pm = NULL;
1622 LPMONITOR_INFO_2W mi2w;
1623 HKEY hroot = NULL;
1624 HKEY hentry = NULL;
1625 DWORD disposition;
1626 BOOL res = FALSE;
1628 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1629 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1630 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
1632 if (copy_servername_from_name(pName, NULL)) {
1633 FIXME("server %s not supported\n", debugstr_w(pName));
1634 SetLastError(ERROR_ACCESS_DENIED);
1635 return FALSE;
1638 if (!mi2w->pName || (! mi2w->pName[0])) {
1639 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1640 SetLastError(ERROR_INVALID_PARAMETER);
1641 return FALSE;
1644 env = validate_envW(mi2w->pEnvironment);
1645 if (!env)
1646 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1648 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1649 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1650 SetLastError(ERROR_INVALID_PARAMETER);
1651 return FALSE;
1654 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1655 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1656 return FALSE;
1659 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1660 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1661 &disposition) == ERROR_SUCCESS) {
1663 /* Some installers set options for the port before calling AddMonitor.
1664 We query the "Driver" entry to verify that the monitor is installed,
1665 before we return an error.
1666 When a user installs two print monitors at the same time with the
1667 same name, a race condition is possible but silently ignored. */
1669 DWORD namesize = 0;
1671 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1672 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1673 &namesize) == ERROR_SUCCESS)) {
1674 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1675 /* 9x use ERROR_ALREADY_EXISTS */
1676 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1678 else
1680 INT len;
1681 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1682 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1683 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1685 /* Load and initialize the monitor. SetLastError() is called on failure */
1686 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL)
1688 RegDeleteKeyW(hroot, mi2w->pName);
1689 res = FALSE;
1691 else
1692 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
1695 RegCloseKey(hentry);
1698 RegCloseKey(hroot);
1699 return (res);
1702 static BOOL wrap_AddPort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR monitor_name)
1704 if (pm->monitor.pfnAddPort)
1705 return pm->monitor.pfnAddPort(pm->hmon, name, hwnd, monitor_name);
1707 if (pm->old_AddPort)
1708 return pm->old_AddPort(name, hwnd, monitor_name);
1710 WARN("AddPort is not implemented by monitor\n");
1711 return FALSE;
1714 /******************************************************************************
1715 * fpAddPort [exported through PRINTPROVIDOR]
1717 * Add a Port for a specific Monitor
1719 * PARAMS
1720 * pName [I] Servername or NULL (local Computer)
1721 * hWnd [I] Handle to parent Window for the Dialog-Box
1722 * pMonitorName [I] Name of the Monitor that manage the Port
1724 * RETURNS
1725 * Success: TRUE
1726 * Failure: FALSE
1729 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1731 monitor_t * pm;
1732 monitor_t * pui;
1733 LONG lres;
1734 DWORD res;
1736 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1738 lres = copy_servername_from_name(pName, NULL);
1739 if (lres) {
1740 FIXME("server %s not supported\n", debugstr_w(pName));
1741 SetLastError(ERROR_INVALID_PARAMETER);
1742 return FALSE;
1745 /* an empty Monitorname is Invalid */
1746 if (!pMonitorName[0]) {
1747 SetLastError(ERROR_NOT_SUPPORTED);
1748 return FALSE;
1751 pm = monitor_load(pMonitorName, NULL);
1752 if (pm && (pm->monitor.pfnAddPort || pm->old_AddPort)) {
1753 res = wrap_AddPort(pm, pName, hWnd, pMonitorName);
1754 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1756 else
1758 pui = monitor_loadui(pm);
1759 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1760 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1761 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1763 else
1765 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1766 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1767 pui, debugstr_w(pui ? pui->dllname : NULL));
1769 SetLastError(ERROR_NOT_SUPPORTED);
1770 res = FALSE;
1772 monitor_unload(pui);
1774 monitor_unload(pm);
1776 TRACE("returning %d with %u\n", res, GetLastError());
1777 return res;
1780 static BOOL wrap_AddPortEx(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer, LPWSTR monitor_name)
1782 if (pm->monitor.pfnAddPortEx)
1783 return pm->monitor.pfnAddPortEx(pm->hmon, name, level, buffer, monitor_name);
1785 if (pm->old_AddPortEx)
1786 return pm->old_AddPortEx(name, level, buffer, monitor_name);
1788 WARN("AddPortEx is not implemented by monitor\n");
1789 return FALSE;
1792 /******************************************************************************
1793 * fpAddPortEx [exported through PRINTPROVIDOR]
1795 * Add a Port for a specific Monitor, without presenting a user interface
1797 * PARAMS
1798 * pName [I] Servername or NULL (local Computer)
1799 * level [I] Structure-Level (1 or 2) for pBuffer
1800 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1801 * pMonitorName [I] Name of the Monitor that manage the Port
1803 * RETURNS
1804 * Success: TRUE
1805 * Failure: FALSE
1808 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1810 PORT_INFO_2W * pi2;
1811 monitor_t * pm;
1812 DWORD lres;
1813 DWORD res;
1815 pi2 = (PORT_INFO_2W *) pBuffer;
1817 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1818 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1819 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1820 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1822 lres = copy_servername_from_name(pName, NULL);
1823 if (lres) {
1824 FIXME("server %s not supported\n", debugstr_w(pName));
1825 SetLastError(ERROR_INVALID_PARAMETER);
1826 return FALSE;
1829 if ((level < 1) || (level > 2)) {
1830 SetLastError(ERROR_INVALID_LEVEL);
1831 return FALSE;
1834 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1835 SetLastError(ERROR_INVALID_PARAMETER);
1836 return FALSE;
1839 /* load the Monitor */
1840 pm = monitor_load(pMonitorName, NULL);
1841 if (pm && (pm->monitor.pfnAddPortEx || pm->old_AddPortEx))
1843 res = wrap_AddPortEx(pm, pName, level, pBuffer, pMonitorName);
1844 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1846 else
1848 FIXME("not implemented for %s (monitor %p: %s)\n",
1849 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
1850 SetLastError(ERROR_INVALID_PARAMETER);
1851 res = FALSE;
1853 monitor_unload(pm);
1854 return res;
1857 /******************************************************************************
1858 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1860 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1862 * PARAMS
1863 * pName [I] Servername or NULL (local Computer)
1864 * level [I] Level for the supplied DRIVER_INFO_*W struct
1865 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1866 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1868 * RESULTS
1869 * Success: TRUE
1870 * Failure: FALSE
1873 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1875 LONG lres;
1877 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1878 lres = copy_servername_from_name(pName, NULL);
1879 if (lres) {
1880 FIXME("server %s not supported\n", debugstr_w(pName));
1881 SetLastError(ERROR_ACCESS_DENIED);
1882 return FALSE;
1885 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1886 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1889 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1892 /******************************************************************************
1893 * fpClosePrinter [exported through PRINTPROVIDOR]
1895 * Close a printer handle and free associated resources
1897 * PARAMS
1898 * hPrinter [I] Printerhandle to close
1900 * RESULTS
1901 * Success: TRUE
1902 * Failure: FALSE
1905 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1907 printer_t *printer = (printer_t *) hPrinter;
1909 TRACE("(%p)\n", hPrinter);
1911 if (printer) {
1912 printer_free(printer);
1913 return TRUE;
1915 return FALSE;
1918 static BOOL wrap_ConfigurePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
1920 if (pm->monitor.pfnConfigurePort)
1921 return pm->monitor.pfnConfigurePort(pm->hmon, name, hwnd, port_name);
1923 if (pm->old_ConfigurePort)
1924 return pm->old_ConfigurePort(name, hwnd, port_name);
1926 WARN("ConfigurePort is not implemented by monitor\n");
1927 return FALSE;
1930 /******************************************************************************
1931 * fpConfigurePort [exported through PRINTPROVIDOR]
1933 * Display the Configuration-Dialog for a specific Port
1935 * PARAMS
1936 * pName [I] Servername or NULL (local Computer)
1937 * hWnd [I] Handle to parent Window for the Dialog-Box
1938 * pPortName [I] Name of the Port, that should be configured
1940 * RETURNS
1941 * Success: TRUE
1942 * Failure: FALSE
1945 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1947 monitor_t * pm;
1948 monitor_t * pui;
1949 LONG lres;
1950 DWORD res;
1952 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1954 lres = copy_servername_from_name(pName, NULL);
1955 if (lres) {
1956 FIXME("server %s not supported\n", debugstr_w(pName));
1957 SetLastError(ERROR_INVALID_NAME);
1958 return FALSE;
1961 /* an empty Portname is Invalid, but can popup a Dialog */
1962 if (!pPortName[0]) {
1963 SetLastError(ERROR_NOT_SUPPORTED);
1964 return FALSE;
1967 pm = monitor_load_by_port(pPortName);
1968 if (pm && (pm->monitor.pfnConfigurePort || pm->old_ConfigurePort))
1970 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1971 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1972 res = wrap_ConfigurePort(pm, pName, hWnd, pPortName);
1973 TRACE("got %d with %u\n", res, GetLastError());
1975 else
1977 pui = monitor_loadui(pm);
1978 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1979 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1980 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1981 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1982 TRACE("got %d with %u\n", res, GetLastError());
1984 else
1986 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1987 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1988 pui, debugstr_w(pui ? pui->dllname : NULL));
1990 SetLastError(ERROR_NOT_SUPPORTED);
1991 res = FALSE;
1993 monitor_unload(pui);
1995 monitor_unload(pm);
1997 TRACE("returning %d with %u\n", res, GetLastError());
1998 return res;
2001 /******************************************************************
2002 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2004 * Delete a specific Printmonitor from a Printing-Environment
2006 * PARAMS
2007 * pName [I] Servername or NULL (local Computer)
2008 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2009 * pMonitorName [I] Name of the Monitor, that should be deleted
2011 * RETURNS
2012 * Success: TRUE
2013 * Failure: FALSE
2015 * NOTES
2016 * pEnvironment is ignored in Windows for the local Computer.
2020 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2022 monitor_t *pm;
2023 HKEY hroot = NULL;
2024 LONG lres;
2026 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2027 debugstr_w(pMonitorName));
2029 lres = copy_servername_from_name(pName, NULL);
2030 if (lres) {
2031 FIXME("server %s not supported\n", debugstr_w(pName));
2032 SetLastError(ERROR_INVALID_NAME);
2033 return FALSE;
2036 /* pEnvironment is ignored in Windows for the local Computer */
2037 if (!pMonitorName || !pMonitorName[0]) {
2038 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2039 SetLastError(ERROR_INVALID_PARAMETER);
2040 return FALSE;
2043 /* Unload the monitor if it's loaded */
2044 EnterCriticalSection(&monitor_handles_cs);
2045 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
2047 if (pm->name && !lstrcmpW(pMonitorName, pm->name))
2049 monitor_unload(pm);
2050 break;
2053 LeaveCriticalSection(&monitor_handles_cs);
2055 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2056 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2057 return FALSE;
2060 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2061 TRACE("%s deleted\n", debugstr_w(pMonitorName));
2062 RegCloseKey(hroot);
2063 return TRUE;
2066 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
2067 RegCloseKey(hroot);
2069 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2070 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2071 return FALSE;
2074 static BOOL wrap_DeletePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
2076 if (pm->monitor.pfnDeletePort)
2077 return pm->monitor.pfnDeletePort(pm->hmon, name, hwnd, port_name);
2079 if (pm->old_ConfigurePort)
2080 return pm->old_DeletePort(name, hwnd, port_name);
2082 WARN("DeletePort is not implemented by monitor\n");
2083 return FALSE;
2086 /*****************************************************************************
2087 * fpDeletePort [exported through PRINTPROVIDOR]
2089 * Delete a specific Port
2091 * PARAMS
2092 * pName [I] Servername or NULL (local Computer)
2093 * hWnd [I] Handle to parent Window for the Dialog-Box
2094 * pPortName [I] Name of the Port, that should be deleted
2096 * RETURNS
2097 * Success: TRUE
2098 * Failure: FALSE
2101 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2103 monitor_t * pm;
2104 monitor_t * pui;
2105 LONG lres;
2106 DWORD res;
2108 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2110 lres = copy_servername_from_name(pName, NULL);
2111 if (lres) {
2112 FIXME("server %s not supported\n", debugstr_w(pName));
2113 SetLastError(ERROR_INVALID_NAME);
2114 return FALSE;
2117 /* an empty Portname is Invalid */
2118 if (!pPortName[0]) {
2119 SetLastError(ERROR_NOT_SUPPORTED);
2120 return FALSE;
2123 pm = monitor_load_by_port(pPortName);
2124 if (pm && (pm->monitor.pfnDeletePort || pm->old_DeletePort))
2126 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2127 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2128 res = wrap_DeletePort(pm, pName, hWnd, pPortName);
2129 TRACE("got %d with %u\n", res, GetLastError());
2131 else
2133 pui = monitor_loadui(pm);
2134 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2135 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2136 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2137 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2138 TRACE("got %d with %u\n", res, GetLastError());
2140 else
2142 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2143 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2144 pui, debugstr_w(pui ? pui->dllname : NULL));
2146 SetLastError(ERROR_NOT_SUPPORTED);
2147 res = FALSE;
2149 monitor_unload(pui);
2151 monitor_unload(pm);
2153 TRACE("returning %d with %u\n", res, GetLastError());
2154 return res;
2157 /*****************************************************************************
2158 * fpEnumMonitors [exported through PRINTPROVIDOR]
2160 * Enumerate available Port-Monitors
2162 * PARAMS
2163 * pName [I] Servername or NULL (local Computer)
2164 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2165 * pMonitors [O] PTR to Buffer that receives the Result
2166 * cbBuf [I] Size of Buffer at pMonitors
2167 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2168 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2170 * RETURNS
2171 * Success: TRUE
2172 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2174 * NOTES
2175 * Windows reads the Registry once and cache the Results.
2178 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
2179 LPDWORD pcbNeeded, LPDWORD pcReturned)
2181 DWORD numentries = 0;
2182 DWORD needed = 0;
2183 LONG lres;
2184 BOOL res = FALSE;
2186 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
2187 cbBuf, pcbNeeded, pcReturned);
2189 lres = copy_servername_from_name(pName, NULL);
2190 if (lres) {
2191 FIXME("server %s not supported\n", debugstr_w(pName));
2192 SetLastError(ERROR_INVALID_NAME);
2193 goto em_cleanup;
2196 if (!Level || (Level > 2)) {
2197 WARN("level (%d) is ignored in win9x\n", Level);
2198 SetLastError(ERROR_INVALID_LEVEL);
2199 return FALSE;
2202 /* Scan all Monitor-Keys */
2203 numentries = 0;
2204 needed = get_local_monitors(Level, NULL, 0, &numentries);
2206 /* we calculated the needed buffersize. now do more error-checks */
2207 if (cbBuf < needed) {
2208 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2209 goto em_cleanup;
2212 /* fill the Buffer with the Monitor-Keys */
2213 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2214 res = TRUE;
2216 em_cleanup:
2217 if (pcbNeeded) *pcbNeeded = needed;
2218 if (pcReturned) *pcReturned = numentries;
2220 TRACE("returning %d with %d (%d byte for %d entries)\n",
2221 res, GetLastError(), needed, numentries);
2223 return (res);
2226 /******************************************************************************
2227 * fpEnumPorts [exported through PRINTPROVIDOR]
2229 * Enumerate available Ports
2231 * PARAMS
2232 * pName [I] Servername or NULL (local Computer)
2233 * Level [I] Structure-Level (1 or 2)
2234 * pPorts [O] PTR to Buffer that receives the Result
2235 * cbBuf [I] Size of Buffer at pPorts
2236 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2237 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2239 * RETURNS
2240 * Success: TRUE
2241 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2244 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2245 LPDWORD pcbNeeded, LPDWORD pcReturned)
2247 DWORD needed = 0;
2248 DWORD numentries = 0;
2249 LONG lres;
2250 BOOL res = FALSE;
2252 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2253 cbBuf, pcbNeeded, pcReturned);
2255 lres = copy_servername_from_name(pName, NULL);
2256 if (lres) {
2257 FIXME("server %s not supported\n", debugstr_w(pName));
2258 SetLastError(ERROR_INVALID_NAME);
2259 goto emP_cleanup;
2262 if (!Level || (Level > 2)) {
2263 SetLastError(ERROR_INVALID_LEVEL);
2264 goto emP_cleanup;
2267 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2268 SetLastError(RPC_X_NULL_REF_POINTER);
2269 goto emP_cleanup;
2272 EnterCriticalSection(&monitor_handles_cs);
2273 monitor_loadall();
2275 /* Scan all local Ports */
2276 numentries = 0;
2277 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2279 /* we calculated the needed buffersize. now do the error-checks */
2280 if (cbBuf < needed) {
2281 monitor_unloadall();
2282 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2283 goto emP_cleanup_cs;
2285 else if (!pPorts || !pcReturned) {
2286 monitor_unloadall();
2287 SetLastError(RPC_X_NULL_REF_POINTER);
2288 goto emP_cleanup_cs;
2291 /* Fill the Buffer */
2292 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2293 res = TRUE;
2294 monitor_unloadall();
2296 emP_cleanup_cs:
2297 LeaveCriticalSection(&monitor_handles_cs);
2299 emP_cleanup:
2300 if (pcbNeeded) *pcbNeeded = needed;
2301 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2303 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2304 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2306 return (res);
2309 /*****************************************************************************
2310 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2312 * Enumerate available Print Processors
2314 * PARAMS
2315 * pName [I] Servername or NULL (local Computer)
2316 * pEnvironment [I] Printing-Environment or NULL (Default)
2317 * Level [I] Structure-Level (Only 1 is allowed)
2318 * pPPInfo [O] PTR to Buffer that receives the Result
2319 * cbBuf [I] Size of Buffer at pMonitors
2320 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2321 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2323 * RETURNS
2324 * Success: TRUE
2325 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2328 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2329 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2331 const printenv_t * env;
2332 LPWSTR regpathW = NULL;
2333 DWORD numentries = 0;
2334 DWORD needed = 0;
2335 LONG lres;
2336 BOOL res = FALSE;
2338 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2339 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2341 lres = copy_servername_from_name(pName, NULL);
2342 if (lres) {
2343 FIXME("server %s not supported\n", debugstr_w(pName));
2344 SetLastError(ERROR_INVALID_NAME);
2345 goto epp_cleanup;
2348 if (Level != 1) {
2349 SetLastError(ERROR_INVALID_LEVEL);
2350 goto epp_cleanup;
2353 env = validate_envW(pEnvironment);
2354 if (!env)
2355 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2357 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2358 (lstrlenW(env->envname) * sizeof(WCHAR)));
2360 if (!regpathW)
2361 goto epp_cleanup;
2363 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2365 /* Scan all Printprocessor-Keys */
2366 numentries = 0;
2367 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2369 /* we calculated the needed buffersize. now do more error-checks */
2370 if (cbBuf < needed) {
2371 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2372 goto epp_cleanup;
2375 /* fill the Buffer with the Printprocessor Infos */
2376 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2377 res = TRUE;
2379 epp_cleanup:
2380 heap_free(regpathW);
2381 if (pcbNeeded) *pcbNeeded = needed;
2382 if (pcReturned) *pcReturned = numentries;
2384 TRACE("returning %d with %d (%d byte for %d entries)\n",
2385 res, GetLastError(), needed, numentries);
2387 return (res);
2390 /******************************************************************************
2391 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2393 * Return the PATH for the Print-Processors
2395 * PARAMS
2396 * pName [I] Servername or NULL (this computer)
2397 * pEnvironment [I] Printing-Environment or NULL (Default)
2398 * level [I] Structure-Level (must be 1)
2399 * pPPInfo [O] PTR to Buffer that receives the Result
2400 * cbBuf [I] Size of Buffer at pPPInfo
2401 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2403 * RETURNS
2404 * Success: TRUE
2405 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2407 * Native Values returned in pPPInfo on Success for this computer:
2408 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2409 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2410 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2412 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2415 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2416 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2418 const printenv_t * env;
2419 DWORD needed;
2420 LONG lres;
2422 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2423 level, pPPInfo, cbBuf, pcbNeeded);
2425 *pcbNeeded = 0;
2426 lres = copy_servername_from_name(pName, NULL);
2427 if (lres) {
2428 FIXME("server %s not supported\n", debugstr_w(pName));
2429 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2430 return FALSE;
2433 env = validate_envW(pEnvironment);
2434 if (!env)
2435 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2437 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2438 needed = GetSystemDirectoryW(NULL, 0);
2439 /* add the Size for the Subdirectories */
2440 needed += lstrlenW(spoolprtprocsW);
2441 needed += lstrlenW(env->subdir);
2442 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2444 *pcbNeeded = needed;
2446 if (needed > cbBuf) {
2447 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2448 return FALSE;
2451 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2452 /* add the Subdirectories */
2453 lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
2454 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2455 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2456 return TRUE;
2459 /******************************************************************************
2460 * fpOpenPrinter [exported through PRINTPROVIDOR]
2462 * Open a Printer / Printserver or a Printer-Object
2464 * PARAMS
2465 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2466 * pPrinter [O] The resulting Handle is stored here
2467 * pDefaults [I] PTR to Default Printer Settings or NULL
2469 * RETURNS
2470 * Success: TRUE
2471 * Failure: FALSE
2473 * NOTES
2474 * lpPrinterName is one of:
2475 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2476 *| Printer: "PrinterName"
2477 *| Printer-Object: "PrinterName,Job xxx"
2478 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2479 *| XcvPort: "Servername,XcvPort PortName"
2483 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2484 LPPRINTER_DEFAULTSW pDefaults)
2487 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2489 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2491 return (*pPrinter != 0);
2494 /******************************************************************************
2495 * fpXcvData [exported through PRINTPROVIDOR]
2497 * Execute commands in the Printmonitor DLL
2499 * PARAMS
2500 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2501 * pszDataName [i] Name of the command to execute
2502 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2503 * cbInputData [i] Size in Bytes of Buffer at pInputData
2504 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2505 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2506 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2507 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2509 * RETURNS
2510 * Success: TRUE
2511 * Failure: FALSE
2513 * NOTES
2514 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2515 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2517 * Minimal List of commands, that a Printmonitor DLL should support:
2519 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2520 *| "AddPort" : Add a Port
2521 *| "DeletePort": Delete a Port
2523 * Many Printmonitors support additional commands. Examples for localspl.dll:
2524 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2525 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2528 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2529 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2530 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2532 printer_t *printer = (printer_t * ) hXcv;
2534 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2535 pInputData, cbInputData, pOutputData,
2536 cbOutputData, pcbOutputNeeded, pdwStatus);
2538 if (!printer || (!printer->hXcv)) {
2539 SetLastError(ERROR_INVALID_HANDLE);
2540 return FALSE;
2543 if (!pcbOutputNeeded) {
2544 SetLastError(ERROR_INVALID_PARAMETER);
2545 return FALSE;
2548 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2549 SetLastError(RPC_X_NULL_REF_POINTER);
2550 return FALSE;
2553 *pcbOutputNeeded = 0;
2555 if (printer->pm->monitor.pfnXcvDataPort)
2556 *pdwStatus = printer->pm->monitor.pfnXcvDataPort(printer->hXcv, pszDataName,
2557 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2559 return TRUE;
2562 /*****************************************************
2563 * setup_provider [internal]
2565 void setup_provider(void)
2567 static const PRINTPROVIDOR backend = {
2568 fpOpenPrinter,
2569 NULL, /* fpSetJob */
2570 NULL, /* fpGetJob */
2571 NULL, /* fpEnumJobs */
2572 NULL, /* fpAddPrinter */
2573 NULL, /* fpDeletePrinter */
2574 NULL, /* fpSetPrinter */
2575 NULL, /* fpGetPrinter */
2576 NULL, /* fpEnumPrinters */
2577 NULL, /* fpAddPrinterDriver */
2578 NULL, /* fpEnumPrinterDrivers */
2579 NULL, /* fpGetPrinterDriver */
2580 fpGetPrinterDriverDirectory,
2581 NULL, /* fpDeletePrinterDriver */
2582 NULL, /* fpAddPrintProcessor */
2583 fpEnumPrintProcessors,
2584 fpGetPrintProcessorDirectory,
2585 NULL, /* fpDeletePrintProcessor */
2586 NULL, /* fpEnumPrintProcessorDatatypes */
2587 NULL, /* fpStartDocPrinter */
2588 NULL, /* fpStartPagePrinter */
2589 NULL, /* fpWritePrinter */
2590 NULL, /* fpEndPagePrinter */
2591 NULL, /* fpAbortPrinter */
2592 NULL, /* fpReadPrinter */
2593 NULL, /* fpEndDocPrinter */
2594 NULL, /* fpAddJob */
2595 NULL, /* fpScheduleJob */
2596 NULL, /* fpGetPrinterData */
2597 NULL, /* fpSetPrinterData */
2598 NULL, /* fpWaitForPrinterChange */
2599 fpClosePrinter,
2600 NULL, /* fpAddForm */
2601 NULL, /* fpDeleteForm */
2602 NULL, /* fpGetForm */
2603 NULL, /* fpSetForm */
2604 NULL, /* fpEnumForms */
2605 fpEnumMonitors,
2606 fpEnumPorts,
2607 fpAddPort,
2608 fpConfigurePort,
2609 fpDeletePort,
2610 NULL, /* fpCreatePrinterIC */
2611 NULL, /* fpPlayGdiScriptOnPrinterIC */
2612 NULL, /* fpDeletePrinterIC */
2613 NULL, /* fpAddPrinterConnection */
2614 NULL, /* fpDeletePrinterConnection */
2615 NULL, /* fpPrinterMessageBox */
2616 fpAddMonitor,
2617 fpDeleteMonitor,
2618 NULL, /* fpResetPrinter */
2619 NULL, /* fpGetPrinterDriverEx */
2620 NULL, /* fpFindFirstPrinterChangeNotification */
2621 NULL, /* fpFindClosePrinterChangeNotification */
2622 fpAddPortEx,
2623 NULL, /* fpShutDown */
2624 NULL, /* fpRefreshPrinterChangeNotification */
2625 NULL, /* fpOpenPrinterEx */
2626 NULL, /* fpAddPrinterEx */
2627 NULL, /* fpSetPort */
2628 NULL, /* fpEnumPrinterData */
2629 NULL, /* fpDeletePrinterData */
2630 NULL, /* fpClusterSplOpen */
2631 NULL, /* fpClusterSplClose */
2632 NULL, /* fpClusterSplIsAlive */
2633 NULL, /* fpSetPrinterDataEx */
2634 NULL, /* fpGetPrinterDataEx */
2635 NULL, /* fpEnumPrinterDataEx */
2636 NULL, /* fpEnumPrinterKey */
2637 NULL, /* fpDeletePrinterDataEx */
2638 NULL, /* fpDeletePrinterKey */
2639 NULL, /* fpSeekPrinter */
2640 NULL, /* fpDeletePrinterDriverEx */
2641 NULL, /* fpAddPerMachineConnection */
2642 NULL, /* fpDeletePerMachineConnection */
2643 NULL, /* fpEnumPerMachineConnections */
2644 fpXcvData,
2645 fpAddPrinterDriverEx,
2646 NULL, /* fpSplReadPrinter */
2647 NULL, /* fpDriverUnloadComplete */
2648 NULL, /* fpGetSpoolFileInfo */
2649 NULL, /* fpCommitSpoolData */
2650 NULL, /* fpCloseSpoolFileHandle */
2651 NULL, /* fpFlushPrinter */
2652 NULL, /* fpSendRecvBidiData */
2653 NULL /* fpAddDriverCatalog */
2655 pprovider = &backend;
2659 /*****************************************************
2660 * InitializePrintProvidor (localspl.@)
2662 * Initialize the Printprovider
2664 * PARAMS
2665 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2666 * cbPrintProvidor [I] Size of Buffer in Bytes
2667 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2669 * RETURNS
2670 * Success: TRUE and pPrintProvidor filled
2671 * Failure: FALSE
2673 * NOTES
2674 * The RegistryPath should be:
2675 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2676 * but this Parameter is ignored in "localspl.dll".
2680 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2681 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2684 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2685 memcpy(pPrintProvidor, pprovider,
2686 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2688 return TRUE;