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
24 #define NONAMELESSUNION
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
42 /* ############################### */
44 static CRITICAL_SECTION monitor_handles_cs;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
47 0, 0, &monitor_handles_cs,
48 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
49 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
51 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
53 /* ############################### */
56 WCHAR src[MAX_PATH+MAX_PATH];
57 WCHAR dst[MAX_PATH+MAX_PATH];
79 LPCWSTR versionregpath;
80 LPCWSTR versionsubdir;
90 /* ############################### */
92 static struct list monitor_handles = LIST_INIT( monitor_handles );
93 static monitor_t * pm_localport;
95 static const PRINTPROVIDOR * pprovider = NULL;
97 static const WCHAR backslashW[] = {'\\',0};
98 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
106 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
107 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
108 'c','o','n','t','r','o','l','\\',
109 'P','r','i','n','t','\\',
110 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
111 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
112 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
113 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
114 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
115 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
116 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
117 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
118 static const WCHAR monitorsW[] = {'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 'M','o','n','i','t','o','r','s','\\',0};
123 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
124 static const WCHAR nameW[] = {'N','a','m','e',0};
125 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
126 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
127 static const WCHAR portW[] = {'P','o','r','t',0};
128 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
129 static const WCHAR printersW[] = {'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 'P','r','i','n','t','e','r','s',0};
134 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
135 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
136 static const WCHAR version0_subdirW[] = {'\\','0',0};
137 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
138 static const WCHAR version3_subdirW[] = {'\\','3',0};
139 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
140 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
141 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
142 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
143 'M','i','c','r','o','s','o','f','t','\\',
144 'W','i','n','d','o','w','s',' ','N','T','\\',
145 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
146 'P','o','r','t','s',0};
147 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
148 static const WCHAR x64_subdirW[] = {'x','6','4',0};
149 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
150 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
151 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
152 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
155 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
156 version3_regpathW, version3_subdirW};
158 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
159 version3_regpathW, version3_subdirW};
161 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
162 version0_regpathW, version0_subdirW};
164 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
167 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
168 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
169 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
170 0, sizeof(DRIVER_INFO_8W)};
173 /******************************************************************
176 * create a copy of a unicode-string
179 static LPWSTR strdupW(LPCWSTR p)
185 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
186 ret = heap_alloc(len);
191 /******************************************************************
192 * apd_copyfile [internal]
194 * Copy a file from the driverdirectory to the versioned directory
201 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
207 apd->src[apd->srclen] = '\0';
208 apd->dst[apd->dstlen] = '\0';
210 if (!filename || !filename[0]) {
211 /* nothing to copy */
215 ptr = strrchrW(filename, '\\');
224 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
225 /* we have an absolute Path */
231 lstrcatW(srcname, ptr);
233 lstrcatW(apd->dst, ptr);
235 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
237 /* FIXME: handle APD_COPY_NEW_FILES */
238 res = CopyFileW(srcname, apd->dst, FALSE);
239 TRACE("got %u with %u\n", res, GetLastError());
241 return (apd->lazy) ? TRUE : res;
244 /******************************************************************
245 * copy_servername_from_name (internal)
247 * for an external server, the serverpart from the name is copied.
250 * the length (in WCHAR) of the serverpart (0 for the local computer)
251 * (-length), when the name is to long
254 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
258 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
262 if (target) *target = '\0';
264 if (name == NULL) return 0;
265 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
268 /* skip over both backslash, find separator '\' */
269 ptr = strchrW(server, '\\');
270 serverlen = (ptr) ? ptr - server : lstrlenW(server);
272 /* servername is empty */
273 if (serverlen == 0) return 0;
275 TRACE("found %s\n", debugstr_wn(server, serverlen));
277 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
280 memcpy(target, server, serverlen * sizeof(WCHAR));
281 target[serverlen] = '\0';
284 len = sizeof(buffer) / sizeof(buffer[0]);
285 if (GetComputerNameW(buffer, &len)) {
286 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
287 /* The requested Servername is our computername */
294 /******************************************************************
295 * get_basename_from_name (internal)
297 * skip over the serverpart from the full name
300 static LPCWSTR get_basename_from_name(LPCWSTR name)
302 if (name == NULL) return NULL;
303 if ((name[0] == '\\') && (name[1] == '\\')) {
304 /* skip over the servername and search for the following '\' */
305 name = strchrW(&name[2], '\\');
306 if ((name) && (name[1])) {
307 /* found a separator ('\') followed by a name:
308 skip over the separator and return the rest */
313 /* no basename present (we found only a servername) */
320 /******************************************************************
321 * monitor_unload [internal]
323 * release a printmonitor and unload it from memory, when needed
326 static void monitor_unload(monitor_t * pm)
328 if (pm == NULL) return;
329 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
331 EnterCriticalSection(&monitor_handles_cs);
333 if (pm->refcount) pm->refcount--;
335 if (pm->refcount == 0) {
336 list_remove(&pm->entry);
337 FreeLibrary(pm->hdll);
339 heap_free(pm->dllname);
342 LeaveCriticalSection(&monitor_handles_cs);
345 /******************************************************************
346 * monitor_unloadall [internal]
348 * release all printmonitors and unload them from memory, when needed
352 static void monitor_unloadall(void)
357 EnterCriticalSection(&monitor_handles_cs);
358 /* iterate through the list, with safety against removal */
359 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
363 LeaveCriticalSection(&monitor_handles_cs);
366 /******************************************************************
367 * monitor_load [internal]
369 * load a printmonitor, get the dllname from the registry, when needed
370 * initialize the monitor and dump found function-pointers
372 * On failure, SetLastError() is called and NULL is returned
375 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
377 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
378 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
379 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
380 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
381 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
383 monitor_t * pm = NULL;
385 LPWSTR regroot = NULL;
386 LPWSTR driver = dllname;
388 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
389 /* Is the Monitor already loaded? */
390 EnterCriticalSection(&monitor_handles_cs);
393 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
395 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
403 pm = heap_alloc_zero(sizeof(monitor_t));
404 if (pm == NULL) goto cleanup;
405 list_add_tail(&monitor_handles, &pm->entry);
409 if (pm->name == NULL) {
410 /* Load the monitor */
411 LPMONITOREX pmonitorEx;
415 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
416 regroot = heap_alloc(len * sizeof(WCHAR));
420 lstrcpyW(regroot, monitorsW);
421 lstrcatW(regroot, name);
422 /* Get the Driver from the Registry */
423 if (driver == NULL) {
426 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
427 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
428 &namesize) == ERROR_SUCCESS) {
429 driver = heap_alloc(namesize);
430 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
437 pm->name = strdupW(name);
438 pm->dllname = strdupW(driver);
440 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
442 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
447 pm->hdll = LoadLibraryW(driver);
448 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
450 if (pm->hdll == NULL) {
452 SetLastError(ERROR_MOD_NOT_FOUND);
457 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
458 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
459 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
460 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
461 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
464 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
465 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
466 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
467 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
468 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
470 if (pInitializePrintMonitorUI != NULL) {
471 pm->monitorUI = pInitializePrintMonitorUI();
472 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
474 TRACE("0x%08x: dwMonitorSize (%d)\n",
475 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
480 if (pInitializePrintMonitor && regroot) {
481 pmonitorEx = pInitializePrintMonitor(regroot);
482 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
483 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
486 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
487 pm->monitor = &(pmonitorEx->Monitor);
492 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
496 if (!pm->monitor && regroot) {
497 if (pInitializePrintMonitor2 != NULL) {
498 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
500 if (pInitializeMonitorEx != NULL) {
501 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
503 if (pInitializeMonitor != NULL) {
504 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
507 if (!pm->monitor && !pm->monitorUI) {
509 SetLastError(ERROR_PROC_NOT_FOUND);
514 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
518 LeaveCriticalSection(&monitor_handles_cs);
519 if (driver != dllname) heap_free(driver);
521 TRACE("=> %p\n", pm);
525 /******************************************************************
526 * monitor_loadall [internal]
528 * Load all registered monitors
531 static DWORD monitor_loadall(void)
534 DWORD registered = 0;
537 WCHAR buffer[MAX_PATH];
540 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
541 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
542 NULL, NULL, NULL, NULL, NULL);
544 TRACE("%d monitors registered\n", registered);
546 while (id < registered) {
548 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
549 pm = monitor_load(buffer, NULL);
553 RegCloseKey(hmonitors);
555 TRACE("%d monitors loaded\n", loaded);
559 /******************************************************************
560 * monitor_load_by_port [internal]
562 * load a printmonitor for a given port
564 * On failure, NULL is returned
567 static monitor_t * monitor_load_by_port(LPCWSTR portname)
572 monitor_t * pm = NULL;
573 DWORD registered = 0;
577 TRACE("(%s)\n", debugstr_w(portname));
579 /* Try the Local Monitor first */
580 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
581 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
582 /* found the portname */
584 return monitor_load(localportW, NULL);
589 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
590 buffer = heap_alloc(len * sizeof(WCHAR));
591 if (buffer == NULL) return NULL;
593 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
594 EnterCriticalSection(&monitor_handles_cs);
595 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
597 while ((pm == NULL) && (id < registered)) {
599 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
600 TRACE("testing %s\n", debugstr_w(buffer));
601 len = lstrlenW(buffer);
602 lstrcatW(buffer, bs_ports_bsW);
603 lstrcatW(buffer, portname);
604 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
606 buffer[len] = '\0'; /* use only the Monitor-Name */
607 pm = monitor_load(buffer, NULL);
611 LeaveCriticalSection(&monitor_handles_cs);
618 /******************************************************************
619 * Return the number of bytes for an multi_sz string.
620 * The result includes all \0s
621 * (specifically the extra \0, that is needed as multi_sz terminator).
623 static int multi_sz_lenW(const WCHAR *str)
625 const WCHAR *ptr = str;
629 ptr += lstrlenW(ptr) + 1;
632 return (ptr - str + 1) * sizeof(WCHAR);
635 /******************************************************************
636 * validate_envW [internal]
638 * validate the user-supplied printing-environment
641 * env [I] PTR to Environment-String or NULL
644 * Success: PTR to printenv_t
645 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
648 * An empty string is handled the same way as NULL.
652 static const printenv_t * validate_envW(LPCWSTR env)
654 const printenv_t *result = NULL;
657 TRACE("(%s)\n", debugstr_w(env));
660 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
662 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
664 result = all_printenv[i];
668 if (result == NULL) {
669 FIXME("unsupported Environment: %s\n", debugstr_w(env));
670 SetLastError(ERROR_INVALID_ENVIRONMENT);
672 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
676 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
679 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
683 /*****************************************************************************
684 * enumerate the local monitors (INTERNAL)
686 * returns the needed size (in bytes) for pMonitors
687 * and *lpreturned is set to number of entries returned in pMonitors
689 * Language-Monitors are also installed in the same Registry-Location but
690 * they are filtered in Windows (not returned by EnumMonitors).
691 * We do no filtering to simplify our Code.
694 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
699 LPMONITOR_INFO_2W mi;
700 WCHAR buffer[MAX_PATH];
701 WCHAR dllname[MAX_PATH];
709 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
711 numentries = *lpreturned; /* this is 0, when we scan the registry */
712 len = entrysize * numentries;
713 ptr = (LPWSTR) &pMonitors[len];
716 len = sizeof(buffer)/sizeof(buffer[0]);
719 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
720 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
721 /* Scan all Monitor-Registry-Keys */
722 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
723 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
724 dllsize = sizeof(dllname);
727 /* The Monitor must have a Driver-DLL */
728 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
729 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
730 /* We found a valid DLL for this Monitor. */
731 TRACE("using Driver: %s\n", debugstr_w(dllname));
736 /* Windows returns only Port-Monitors here, but to simplify our code,
737 we do no filtering for Language-Monitors */
741 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
743 /* we install and return only monitors for "Windows NT x86" */
744 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
748 /* required size is calculated. Now fill the user-buffer */
749 if (pMonitors && (cbBuf >= needed)){
750 mi = (LPMONITOR_INFO_2W) pMonitors;
751 pMonitors += entrysize;
753 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
755 lstrcpyW(ptr, buffer); /* Name of the Monitor */
756 ptr += (len+1); /* len is lstrlenW(monitorname) */
758 mi->pEnvironment = ptr;
759 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
760 ptr += (lstrlenW(x86_envnameW)+1);
763 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
764 ptr += (dllsize / sizeof(WCHAR));
769 len = sizeof(buffer)/sizeof(buffer[0]);
774 *lpreturned = numentries;
775 TRACE("need %d byte for %d entries\n", needed, numentries);
779 /******************************************************************
780 * enumerate the local Ports from all loaded monitors (internal)
782 * returns the needed size (in bytes) for pPorts
783 * and *lpreturned is set to number of entries returned in pPorts
786 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
790 LPPORT_INFO_2W cache;
792 LPBYTE pi_buffer = NULL;
793 DWORD pi_allocated = 0;
804 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
805 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
807 numentries = *lpreturned; /* this is 0, when we scan the registry */
808 needed = entrysize * numentries;
809 ptr = (LPWSTR) &pPorts[needed];
814 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
816 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
819 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
820 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
821 /* Do not use heap_realloc (we do not need the old data in the buffer) */
822 heap_free(pi_buffer);
823 pi_buffer = heap_alloc(pi_needed);
824 pi_allocated = (pi_buffer) ? pi_needed : 0;
825 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
827 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
828 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
830 numentries += pi_returned;
833 /* fill the output-buffer (pPorts), if we have one */
834 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
836 while (pi_returned > pi_index) {
837 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
838 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
839 out->pPortName = ptr;
840 lstrcpyW(ptr, cache->pPortName);
841 ptr += (lstrlenW(ptr)+1);
843 out->pMonitorName = ptr;
844 lstrcpyW(ptr, cache->pMonitorName);
845 ptr += (lstrlenW(ptr)+1);
847 out->pDescription = ptr;
848 lstrcpyW(ptr, cache->pDescription);
849 ptr += (lstrlenW(ptr)+1);
850 out->fPortType = cache->fPortType;
851 out->Reserved = cache->Reserved;
859 /* the temporary portinfo-buffer is no longer needed */
860 heap_free(pi_buffer);
862 *lpreturned = numentries;
863 TRACE("need %d byte for %d entries\n", needed, numentries);
868 /*****************************************************************************
869 * open_driver_reg [internal]
871 * opens the registry for the printer drivers depending on the given input
872 * variable pEnvironment
875 * Success: the opened hkey
878 static HKEY open_driver_reg(LPCWSTR pEnvironment)
882 const printenv_t * env;
884 TRACE("(%s)\n", debugstr_w(pEnvironment));
886 env = validate_envW(pEnvironment);
887 if (!env) return NULL;
889 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
890 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
893 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
894 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
895 HeapFree(GetProcessHeap(), 0, buffer);
900 /*****************************************************************************
901 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
903 * Return the PATH for the Printer-Drivers
906 * pName [I] Servername (NT only) or NULL (local Computer)
907 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
908 * Level [I] Structure-Level (must be 1)
909 * pDriverDirectory [O] PTR to Buffer that receives the Result
910 * cbBuf [I] Size of Buffer at pDriverDirectory
911 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
912 * required for pDriverDirectory
915 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
916 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
917 * if cbBuf is too small
919 * Native Values returned in pDriverDirectory on Success:
920 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
921 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
922 *| win9x(Windows 4.0): "%winsysdir%"
924 * "%winsysdir%" is the Value from GetSystemDirectoryW()
927 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
928 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
931 const printenv_t * env;
933 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
934 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
936 if (pName != NULL && pName[0]) {
937 FIXME("server %s not supported\n", debugstr_w(pName));
938 SetLastError(ERROR_INVALID_PARAMETER);
942 env = validate_envW(pEnvironment);
943 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
946 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
947 needed = GetSystemDirectoryW(NULL, 0);
948 /* add the Size for the Subdirectories */
949 needed += lstrlenW(spooldriversW);
950 needed += lstrlenW(env->subdir);
951 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
955 if (needed > cbBuf) {
956 SetLastError(ERROR_INSUFFICIENT_BUFFER);
960 if (pDriverDirectory == NULL) {
961 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
962 SetLastError(ERROR_INVALID_USER_BUFFER);
966 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
967 /* add the Subdirectories */
968 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
969 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
971 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
975 /******************************************************************
976 * driver_load [internal]
978 * load a driver user interface dll
980 * On failure, NULL is returned
984 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
986 WCHAR fullname[MAX_PATH];
990 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
992 /* build the driverdir */
993 len = sizeof(fullname) -
994 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
996 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
997 (LPBYTE) fullname, len, &len)) {
998 /* Should never Fail */
999 SetLastError(ERROR_BUFFER_OVERFLOW);
1003 lstrcatW(fullname, env->versionsubdir);
1004 lstrcatW(fullname, backslashW);
1005 lstrcatW(fullname, dllname);
1007 hui = LoadLibraryW(fullname);
1008 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1013 /******************************************************************
1015 * free the data pointer of an opened printer
1017 static VOID printer_free(printer_t * printer)
1020 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1022 monitor_unload(printer->pm);
1024 heap_free(printer->printername);
1025 heap_free(printer->name);
1029 /******************************************************************
1030 * printer_alloc_handle
1031 * alloc a printer handle and remember the data pointer in the printer handle table
1034 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1036 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1037 printer_t *printer = NULL;
1038 LPCWSTR printername;
1043 if (copy_servername_from_name(name, servername)) {
1044 FIXME("server %s not supported\n", debugstr_w(servername));
1045 SetLastError(ERROR_INVALID_PRINTER_NAME);
1049 printername = get_basename_from_name(name);
1050 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1052 /* an empty printername is invalid */
1053 if (printername && (!printername[0])) {
1054 SetLastError(ERROR_INVALID_PARAMETER);
1058 printer = heap_alloc_zero(sizeof(printer_t));
1059 if (!printer) goto end;
1061 /* clone the base name. This is NULL for the printserver */
1062 printer->printername = strdupW(printername);
1064 /* clone the full name */
1065 printer->name = strdupW(name);
1066 if (name && (!printer->name)) {
1067 printer_free(printer);
1071 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1072 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1073 /* OpenPrinter(",XcvMonitor ", ...) detected */
1074 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1075 printer->pm = monitor_load(&printername[len], NULL);
1076 if (printer->pm == NULL) {
1077 printer_free(printer);
1078 SetLastError(ERROR_UNKNOWN_PORT);
1085 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1086 if (strncmpW( printername, XcvPortW, len) == 0) {
1087 /* OpenPrinter(",XcvPort ", ...) detected */
1088 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1089 printer->pm = monitor_load_by_port(&printername[len]);
1090 if (printer->pm == NULL) {
1091 printer_free(printer);
1092 SetLastError(ERROR_UNKNOWN_PORT);
1100 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1101 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1102 pDefault ? pDefault->DesiredAccess : 0,
1105 if (printer->hXcv == NULL) {
1106 printer_free(printer);
1107 SetLastError(ERROR_INVALID_PARAMETER);
1114 /* Does the Printer exist? */
1115 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1116 ERR("Can't create Printers key\n");
1117 printer_free(printer);
1118 SetLastError(ERROR_INVALID_PRINTER_NAME);
1122 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1123 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1124 RegCloseKey(hkeyPrinters);
1125 printer_free(printer);
1126 SetLastError(ERROR_INVALID_PRINTER_NAME);
1130 RegCloseKey(hkeyPrinter);
1131 RegCloseKey(hkeyPrinters);
1136 TRACE("using the local printserver\n");
1141 TRACE("==> %p\n", printer);
1142 return (HANDLE)printer;
1146 /******************************************************************************
1147 * myAddPrinterDriverEx [internal]
1149 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1150 * and a special mode with lazy error checking.
1153 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1155 static const WCHAR emptyW[1];
1156 const printenv_t *env;
1159 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1169 /* we need to set all entries in the Registry, independent from the Level of
1170 DRIVER_INFO, that the caller supplied */
1172 ZeroMemory(&di, sizeof(di));
1173 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1174 memcpy(&di, pDriverInfo, di_sizeof[level]);
1177 /* dump the most used infos */
1178 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1179 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1180 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1181 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1182 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1183 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1184 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1185 /* dump only the first of the additional Files */
1186 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1189 /* check environment */
1190 env = validate_envW(di.pEnvironment);
1191 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1193 /* fill the copy-data / get the driverdir */
1194 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1195 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1196 (LPBYTE) apd.src, len, &len)) {
1197 /* Should never Fail */
1200 memcpy(apd.dst, apd.src, len);
1201 lstrcatW(apd.src, backslashW);
1202 apd.srclen = lstrlenW(apd.src);
1203 lstrcatW(apd.dst, env->versionsubdir);
1204 lstrcatW(apd.dst, backslashW);
1205 apd.dstlen = lstrlenW(apd.dst);
1206 apd.copyflags = dwFileCopyFlags;
1208 CreateDirectoryW(apd.src, NULL);
1209 CreateDirectoryW(apd.dst, NULL);
1211 hroot = open_driver_reg(env->envname);
1213 ERR("Can't create Drivers key\n");
1217 /* Fill the Registry for the Driver */
1218 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1219 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1220 &hdrv, &disposition)) != ERROR_SUCCESS) {
1222 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1229 if (disposition == REG_OPENED_EXISTING_KEY) {
1230 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1232 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1236 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1237 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1240 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1241 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1242 apd_copyfile(di.pDriverPath, &apd);
1244 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1245 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1246 apd_copyfile(di.pDataFile, &apd);
1248 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1249 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1250 apd_copyfile(di.pConfigFile, &apd);
1252 /* settings for level 3 */
1254 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1255 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1257 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1258 apd_copyfile(di.pHelpFile, &apd);
1261 ptr = di.pDependentFiles;
1263 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1264 multi_sz_lenW(di.pDependentFiles));
1266 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1267 while ((ptr != NULL) && (ptr[0])) {
1268 if (apd_copyfile(ptr, &apd)) {
1269 ptr += lstrlenW(ptr) + 1;
1273 WARN("Failed to copy %s\n", debugstr_w(ptr));
1277 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1278 if (di.pMonitorName)
1279 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1280 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1282 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1284 if (di.pDefaultDataType)
1285 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1286 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1288 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1290 /* settings for level 4 */
1291 if (di.pszzPreviousNames)
1292 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1293 multi_sz_lenW(di.pszzPreviousNames));
1295 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1297 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1300 hui = driver_load(env, di.pConfigFile);
1301 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1302 if (hui && pDrvDriverEvent) {
1304 /* Support for DrvDriverEvent is optional */
1305 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1306 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1307 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1308 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1312 TRACE("=> TRUE with %u\n", GetLastError());
1317 /******************************************************************************
1318 * fpAddMonitor [exported through PRINTPROVIDOR]
1320 * Install a Printmonitor
1323 * pName [I] Servername or NULL (local Computer)
1324 * Level [I] Structure-Level (Must be 2)
1325 * pMonitors [I] PTR to MONITOR_INFO_2
1332 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1335 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1337 monitor_t * pm = NULL;
1338 LPMONITOR_INFO_2W mi2w;
1344 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1345 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1346 debugstr_w(mi2w ? mi2w->pName : NULL),
1347 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1348 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1350 if (copy_servername_from_name(pName, NULL)) {
1351 FIXME("server %s not supported\n", debugstr_w(pName));
1352 SetLastError(ERROR_ACCESS_DENIED);
1356 if (!mi2w->pName || (! mi2w->pName[0])) {
1357 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1358 SetLastError(ERROR_INVALID_PARAMETER);
1361 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1362 WARN("Environment %s requested (we support only %s)\n",
1363 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1364 SetLastError(ERROR_INVALID_ENVIRONMENT);
1368 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1369 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1370 SetLastError(ERROR_INVALID_PARAMETER);
1374 /* Load and initialize the monitor. SetLastError() is called on failure */
1375 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1380 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1381 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1385 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1386 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1387 &disposition) == ERROR_SUCCESS) {
1389 /* Some installers set options for the port before calling AddMonitor.
1390 We query the "Driver" entry to verify that the monitor is installed,
1391 before we return an error.
1392 When a user installs two print monitors at the same time with the
1393 same name, a race condition is possible but silently ignored. */
1397 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1398 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1399 &namesize) == ERROR_SUCCESS)) {
1400 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1401 /* 9x use ERROR_ALREADY_EXISTS */
1402 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1407 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1408 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1409 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1411 RegCloseKey(hentry);
1418 /******************************************************************************
1419 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1421 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1424 * pName [I] Servername or NULL (local Computer)
1425 * level [I] Level for the supplied DRIVER_INFO_*W struct
1426 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1427 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1434 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1438 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1439 lres = copy_servername_from_name(pName, NULL);
1441 FIXME("server %s not supported\n", debugstr_w(pName));
1442 SetLastError(ERROR_ACCESS_DENIED);
1446 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1447 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1450 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1453 /******************************************************************************
1454 * fpClosePrinter [exported through PRINTPROVIDOR]
1456 * Close a printer handle and free associated resources
1459 * hPrinter [I] Printerhandle to close
1466 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1468 printer_t *printer = (printer_t *) hPrinter;
1470 TRACE("(%p)\n", hPrinter);
1473 printer_free(printer);
1480 /******************************************************************
1481 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1483 * Delete a specific Printmonitor from a Printing-Environment
1486 * pName [I] Servername or NULL (local Computer)
1487 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1488 * pMonitorName [I] Name of the Monitor, that should be deleted
1495 * pEnvironment is ignored in Windows for the local Computer.
1499 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1504 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1505 debugstr_w(pMonitorName));
1507 lres = copy_servername_from_name(pName, NULL);
1509 FIXME("server %s not supported\n", debugstr_w(pName));
1510 SetLastError(ERROR_INVALID_NAME);
1514 /* pEnvironment is ignored in Windows for the local Computer */
1515 if (!pMonitorName || !pMonitorName[0]) {
1516 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1517 SetLastError(ERROR_INVALID_PARAMETER);
1521 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1526 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1527 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1532 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1535 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1536 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1540 /*****************************************************************************
1541 * fpEnumMonitors [exported through PRINTPROVIDOR]
1543 * Enumerate available Port-Monitors
1546 * pName [I] Servername or NULL (local Computer)
1547 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1548 * pMonitors [O] PTR to Buffer that receives the Result
1549 * cbBuf [I] Size of Buffer at pMonitors
1550 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1551 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1555 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1558 * Windows reads the Registry once and cache the Results.
1561 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1562 LPDWORD pcbNeeded, LPDWORD pcReturned)
1564 DWORD numentries = 0;
1569 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1570 cbBuf, pcbNeeded, pcReturned);
1572 lres = copy_servername_from_name(pName, NULL);
1574 FIXME("server %s not supported\n", debugstr_w(pName));
1575 SetLastError(ERROR_INVALID_NAME);
1579 if (!Level || (Level > 2)) {
1580 WARN("level (%d) is ignored in win9x\n", Level);
1581 SetLastError(ERROR_INVALID_LEVEL);
1585 /* Scan all Monitor-Keys */
1587 needed = get_local_monitors(Level, NULL, 0, &numentries);
1589 /* we calculated the needed buffersize. now do more error-checks */
1590 if (cbBuf < needed) {
1591 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1595 /* fill the Buffer with the Monitor-Keys */
1596 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1600 if (pcbNeeded) *pcbNeeded = needed;
1601 if (pcReturned) *pcReturned = numentries;
1603 TRACE("returning %d with %d (%d byte for %d entries)\n",
1604 res, GetLastError(), needed, numentries);
1609 /******************************************************************************
1610 * fpEnumPorts [exported through PRINTPROVIDOR]
1612 * Enumerate available Ports
1615 * pName [I] Servername or NULL (local Computer)
1616 * Level [I] Structure-Level (1 or 2)
1617 * pPorts [O] PTR to Buffer that receives the Result
1618 * cbBuf [I] Size of Buffer at pPorts
1619 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1620 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1624 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1627 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1628 LPDWORD pcbNeeded, LPDWORD pcReturned)
1631 DWORD numentries = 0;
1635 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1636 cbBuf, pcbNeeded, pcReturned);
1638 lres = copy_servername_from_name(pName, NULL);
1640 FIXME("server %s not supported\n", debugstr_w(pName));
1641 SetLastError(ERROR_INVALID_NAME);
1645 if (!Level || (Level > 2)) {
1646 SetLastError(ERROR_INVALID_LEVEL);
1650 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1651 SetLastError(RPC_X_NULL_REF_POINTER);
1655 EnterCriticalSection(&monitor_handles_cs);
1658 /* Scan all local Ports */
1660 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1662 /* we calculated the needed buffersize. now do the error-checks */
1663 if (cbBuf < needed) {
1664 monitor_unloadall();
1665 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1666 goto emP_cleanup_cs;
1668 else if (!pPorts || !pcReturned) {
1669 monitor_unloadall();
1670 SetLastError(RPC_X_NULL_REF_POINTER);
1671 goto emP_cleanup_cs;
1674 /* Fill the Buffer */
1675 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1677 monitor_unloadall();
1680 LeaveCriticalSection(&monitor_handles_cs);
1683 if (pcbNeeded) *pcbNeeded = needed;
1684 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1686 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1687 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1692 /******************************************************************************
1693 * fpOpenPrinter [exported through PRINTPROVIDOR]
1695 * Open a Printer / Printserver or a Printer-Object
1698 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1699 * pPrinter [O] The resulting Handle is stored here
1700 * pDefaults [I] PTR to Default Printer Settings or NULL
1707 * lpPrinterName is one of:
1708 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1709 *| Printer: "PrinterName"
1710 *| Printer-Object: "PrinterName,Job xxx"
1711 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1712 *| XcvPort: "Servername,XcvPort PortName"
1716 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
1717 LPPRINTER_DEFAULTSW pDefaults)
1720 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
1722 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
1724 return (*pPrinter != 0);
1727 /******************************************************************************
1728 * fpXcvData [exported through PRINTPROVIDOR]
1730 * Execute commands in the Printmonitor DLL
1733 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
1734 * pszDataName [i] Name of the command to execute
1735 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
1736 * cbInputData [i] Size in Bytes of Buffer at pInputData
1737 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
1738 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
1739 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
1740 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
1747 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
1748 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
1750 * Minimal List of commands, that a Printmonitor DLL should support:
1752 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
1753 *| "AddPort" : Add a Port
1754 *| "DeletePort": Delete a Port
1756 * Many Printmonitors support additional commands. Examples for localspl.dll:
1757 * "GetDefaultCommConfig", "SetDefaultCommConfig",
1758 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
1761 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
1762 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
1763 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1765 printer_t *printer = (printer_t * ) hXcv;
1767 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
1768 pInputData, cbInputData, pOutputData,
1769 cbOutputData, pcbOutputNeeded, pdwStatus);
1771 if (!printer || (!printer->hXcv)) {
1772 SetLastError(ERROR_INVALID_HANDLE);
1776 if (!pcbOutputNeeded) {
1777 SetLastError(ERROR_INVALID_PARAMETER);
1781 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
1782 SetLastError(RPC_X_NULL_REF_POINTER);
1786 *pcbOutputNeeded = 0;
1788 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
1789 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
1794 /*****************************************************
1795 * setup_provider [internal]
1797 void setup_provider(void)
1799 static const PRINTPROVIDOR backend = {
1801 NULL, /* fpSetJob */
1802 NULL, /* fpGetJob */
1803 NULL, /* fpEnumJobs */
1804 NULL, /* fpAddPrinter */
1805 NULL, /* fpDeletePrinter */
1806 NULL, /* fpSetPrinter */
1807 NULL, /* fpGetPrinter */
1808 NULL, /* fpEnumPrinters */
1809 NULL, /* fpAddPrinterDriver */
1810 NULL, /* fpEnumPrinterDrivers */
1811 NULL, /* fpGetPrinterDriver */
1812 fpGetPrinterDriverDirectory,
1813 NULL, /* fpDeletePrinterDriver */
1814 NULL, /* fpAddPrintProcessor */
1815 NULL, /* fpEnumPrintProcessors */
1816 NULL, /* fpGetPrintProcessorDirectory */
1817 NULL, /* fpDeletePrintProcessor */
1818 NULL, /* fpEnumPrintProcessorDatatypes */
1819 NULL, /* fpStartDocPrinter */
1820 NULL, /* fpStartPagePrinter */
1821 NULL, /* fpWritePrinter */
1822 NULL, /* fpEndPagePrinter */
1823 NULL, /* fpAbortPrinter */
1824 NULL, /* fpReadPrinter */
1825 NULL, /* fpEndDocPrinter */
1826 NULL, /* fpAddJob */
1827 NULL, /* fpScheduleJob */
1828 NULL, /* fpGetPrinterData */
1829 NULL, /* fpSetPrinterData */
1830 NULL, /* fpWaitForPrinterChange */
1832 NULL, /* fpAddForm */
1833 NULL, /* fpDeleteForm */
1834 NULL, /* fpGetForm */
1835 NULL, /* fpSetForm */
1836 NULL, /* fpEnumForms */
1839 NULL, /* fpAddPort */
1840 NULL, /* fpConfigurePort */
1841 NULL, /* fpDeletePort */
1842 NULL, /* fpCreatePrinterIC */
1843 NULL, /* fpPlayGdiScriptOnPrinterIC */
1844 NULL, /* fpDeletePrinterIC */
1845 NULL, /* fpAddPrinterConnection */
1846 NULL, /* fpDeletePrinterConnection */
1847 NULL, /* fpPrinterMessageBox */
1850 NULL, /* fpResetPrinter */
1851 NULL, /* fpGetPrinterDriverEx */
1852 NULL, /* fpFindFirstPrinterChangeNotification */
1853 NULL, /* fpFindClosePrinterChangeNotification */
1854 NULL, /* fpAddPortEx */
1855 NULL, /* fpShutDown */
1856 NULL, /* fpRefreshPrinterChangeNotification */
1857 NULL, /* fpOpenPrinterEx */
1858 NULL, /* fpAddPrinterEx */
1859 NULL, /* fpSetPort */
1860 NULL, /* fpEnumPrinterData */
1861 NULL, /* fpDeletePrinterData */
1862 NULL, /* fpClusterSplOpen */
1863 NULL, /* fpClusterSplClose */
1864 NULL, /* fpClusterSplIsAlive */
1865 NULL, /* fpSetPrinterDataEx */
1866 NULL, /* fpGetPrinterDataEx */
1867 NULL, /* fpEnumPrinterDataEx */
1868 NULL, /* fpEnumPrinterKey */
1869 NULL, /* fpDeletePrinterDataEx */
1870 NULL, /* fpDeletePrinterKey */
1871 NULL, /* fpSeekPrinter */
1872 NULL, /* fpDeletePrinterDriverEx */
1873 NULL, /* fpAddPerMachineConnection */
1874 NULL, /* fpDeletePerMachineConnection */
1875 NULL, /* fpEnumPerMachineConnections */
1877 fpAddPrinterDriverEx,
1878 NULL, /* fpSplReadPrinter */
1879 NULL, /* fpDriverUnloadComplete */
1880 NULL, /* fpGetSpoolFileInfo */
1881 NULL, /* fpCommitSpoolData */
1882 NULL, /* fpCloseSpoolFileHandle */
1883 NULL, /* fpFlushPrinter */
1884 NULL, /* fpSendRecvBidiData */
1885 NULL /* fpAddDriverCatalog */
1887 pprovider = &backend;
1891 /*****************************************************
1892 * InitializePrintProvidor (localspl.@)
1894 * Initialize the Printprovider
1897 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1898 * cbPrintProvidor [I] Size of Buffer in Bytes
1899 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1902 * Success: TRUE and pPrintProvidor filled
1906 * The RegistryPath should be:
1907 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1908 * but this Parameter is ignored in "localspl.dll".
1912 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1913 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1916 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1917 memcpy(pPrintProvidor, pprovider,
1918 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));