msi: Fix handling of buffer sizes in MsiEnumPatchesA and avoid a redundant call to...
[wine/multimedia.git] / dlls / localspl / provider.c
blobdcb8b088d37df915417d2e68e7e396bfc666dcf8
1 /*
2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "winuser.h"
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
42 /* ############################### */
44 static CRITICAL_SECTION monitor_handles_cs;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
47 0, 0, &monitor_handles_cs,
48 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
49 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
51 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
53 /* ############################### */
55 typedef struct {
56 WCHAR src[MAX_PATH+MAX_PATH];
57 WCHAR dst[MAX_PATH+MAX_PATH];
58 DWORD srclen;
59 DWORD dstlen;
60 DWORD copyflags;
61 BOOL lazy;
62 } apd_data_t;
64 typedef struct {
65 struct list entry;
66 LPWSTR name;
67 LPWSTR dllname;
68 PMONITORUI monitorUI;
69 LPMONITOR monitor;
70 HMODULE hdll;
71 DWORD refcount;
72 DWORD dwMonitorSize;
73 } monitor_t;
75 typedef struct {
76 LPCWSTR envname;
77 LPCWSTR subdir;
78 DWORD driverversion;
79 LPCWSTR versionregpath;
80 LPCWSTR versionsubdir;
81 } printenv_t;
83 /* ############################### */
85 static struct list monitor_handles = LIST_INIT( monitor_handles );
86 static monitor_t * pm_localport;
88 static const PRINTPROVIDOR * pprovider = NULL;
90 static const WCHAR backslashW[] = {'\\',0};
91 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
92 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
93 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
94 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
95 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
96 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
97 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
98 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
99 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
100 'c','o','n','t','r','o','l','\\',
101 'P','r','i','n','t','\\',
102 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
103 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
104 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
105 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
106 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
107 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
108 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
109 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
110 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
111 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'C','o','n','t','r','o','l','\\',
113 'P','r','i','n','t','\\',
114 'M','o','n','i','t','o','r','s','\\',0};
115 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
116 static const WCHAR nameW[] = {'N','a','m','e',0};
117 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
118 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
119 static const WCHAR portW[] = {'P','o','r','t',0};
120 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
121 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
122 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
124 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
125 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
126 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
127 static const WCHAR version0_subdirW[] = {'\\','0',0};
129 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
130 static const WCHAR x64_subdirW[] = {'x','6','4',0};
131 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
132 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
133 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
134 static const WCHAR version3_subdirW[] = {'\\','3',0};
137 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
138 version3_regpathW, version3_subdirW};
140 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
141 version3_regpathW, version3_subdirW};
143 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
144 version0_regpathW, version0_subdirW};
146 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
149 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
150 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
151 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
152 0, sizeof(DRIVER_INFO_8W)};
155 /******************************************************************
156 * strdupW [internal]
158 * create a copy of a unicode-string
161 static LPWSTR strdupW(LPCWSTR p)
163 LPWSTR ret;
164 DWORD len;
166 if(!p) return NULL;
167 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
168 ret = heap_alloc(len);
169 memcpy(ret, p, len);
170 return ret;
173 /******************************************************************
174 * apd_copyfile [internal]
176 * Copy a file from the driverdirectory to the versioned directory
178 * RETURNS
179 * Success: TRUE
180 * Failure: FALSE
183 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
185 LPWSTR ptr;
186 LPWSTR srcname;
187 DWORD res;
189 apd->src[apd->srclen] = '\0';
190 apd->dst[apd->dstlen] = '\0';
192 if (!filename || !filename[0]) {
193 /* nothing to copy */
194 return TRUE;
197 ptr = strrchrW(filename, '\\');
198 if (ptr) {
199 ptr++;
201 else
203 ptr = filename;
206 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
207 /* we have an absolute Path */
208 srcname = filename;
210 else
212 srcname = apd->src;
213 lstrcatW(srcname, ptr);
215 lstrcatW(apd->dst, ptr);
217 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
219 /* FIXME: handle APD_COPY_NEW_FILES */
220 res = CopyFileW(srcname, apd->dst, FALSE);
221 TRACE("got %u with %u\n", res, GetLastError());
223 return (apd->lazy) ? TRUE : res;
226 /******************************************************************
227 * copy_servername_from_name (internal)
229 * for an external server, the serverpart from the name is copied.
231 * RETURNS
232 * the length (in WCHAR) of the serverpart (0 for the local computer)
233 * (-length), when the name is to long
236 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
238 LPCWSTR server;
239 LPWSTR ptr;
240 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
241 DWORD len;
242 DWORD serverlen;
244 if (target) *target = '\0';
246 if (name == NULL) return 0;
247 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
249 server = &name[2];
250 /* skip over both backslash, find separator '\' */
251 ptr = strchrW(server, '\\');
252 serverlen = (ptr) ? ptr - server : lstrlenW(server);
254 /* servername is empty or to long */
255 if (serverlen == 0) return 0;
257 TRACE("found %s\n", debugstr_wn(server, serverlen));
259 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
261 len = sizeof(buffer) / sizeof(buffer[0]);
262 if (GetComputerNameW(buffer, &len)) {
263 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
264 /* The requested Servername is our computername */
265 if (target) {
266 memcpy(target, server, serverlen * sizeof(WCHAR));
267 target[serverlen] = '\0';
269 return serverlen;
272 return 0;
275 /******************************************************************
276 * monitor_unload [internal]
278 * release a printmonitor and unload it from memory, when needed
281 static void monitor_unload(monitor_t * pm)
283 if (pm == NULL) return;
284 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
286 EnterCriticalSection(&monitor_handles_cs);
288 if (pm->refcount) pm->refcount--;
290 if (pm->refcount == 0) {
291 list_remove(&pm->entry);
292 FreeLibrary(pm->hdll);
293 heap_free(pm->name);
294 heap_free(pm->dllname);
295 heap_free(pm);
297 LeaveCriticalSection(&monitor_handles_cs);
300 /******************************************************************
301 * monitor_unloadall [internal]
303 * release all printmonitors and unload them from memory, when needed
307 static void monitor_unloadall(void)
309 monitor_t * pm;
310 monitor_t * next;
312 EnterCriticalSection(&monitor_handles_cs);
313 /* iterate through the list, with safety against removal */
314 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
316 monitor_unload(pm);
318 LeaveCriticalSection(&monitor_handles_cs);
321 /******************************************************************
322 * monitor_load [internal]
324 * load a printmonitor, get the dllname from the registry, when needed
325 * initialize the monitor and dump found function-pointers
327 * On failure, SetLastError() is called and NULL is returned
330 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
332 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
333 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
334 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
335 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
336 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
338 monitor_t * pm = NULL;
339 monitor_t * cursor;
340 LPWSTR regroot = NULL;
341 LPWSTR driver = dllname;
343 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
344 /* Is the Monitor already loaded? */
345 EnterCriticalSection(&monitor_handles_cs);
347 if (name) {
348 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
350 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
351 pm = cursor;
352 break;
357 if (pm == NULL) {
358 pm = heap_alloc_zero(sizeof(monitor_t));
359 if (pm == NULL) goto cleanup;
360 list_add_tail(&monitor_handles, &pm->entry);
362 pm->refcount++;
364 if (pm->name == NULL) {
365 /* Load the monitor */
366 LPMONITOREX pmonitorEx;
367 DWORD len;
369 if (name) {
370 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
371 regroot = heap_alloc(len * sizeof(WCHAR));
374 if (regroot) {
375 lstrcpyW(regroot, monitorsW);
376 lstrcatW(regroot, name);
377 /* Get the Driver from the Registry */
378 if (driver == NULL) {
379 HKEY hroot;
380 DWORD namesize;
381 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
382 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
383 &namesize) == ERROR_SUCCESS) {
384 driver = heap_alloc(namesize);
385 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
387 RegCloseKey(hroot);
392 pm->name = strdupW(name);
393 pm->dllname = strdupW(driver);
395 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
396 monitor_unload(pm);
397 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
398 pm = NULL;
399 goto cleanup;
402 pm->hdll = LoadLibraryW(driver);
403 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
405 if (pm->hdll == NULL) {
406 monitor_unload(pm);
407 SetLastError(ERROR_MOD_NOT_FOUND);
408 pm = NULL;
409 goto cleanup;
412 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
413 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
414 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
415 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
416 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
419 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
420 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
421 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
422 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
423 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
425 if (pInitializePrintMonitorUI != NULL) {
426 pm->monitorUI = pInitializePrintMonitorUI();
427 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
428 if (pm->monitorUI) {
429 TRACE("0x%08x: dwMonitorSize (%d)\n",
430 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
435 if (pInitializePrintMonitor && regroot) {
436 pmonitorEx = pInitializePrintMonitor(regroot);
437 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
438 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
440 if (pmonitorEx) {
441 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
442 pm->monitor = &(pmonitorEx->Monitor);
446 if (pm->monitor) {
447 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
451 if (!pm->monitor && regroot) {
452 if (pInitializePrintMonitor2 != NULL) {
453 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
455 if (pInitializeMonitorEx != NULL) {
456 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
458 if (pInitializeMonitor != NULL) {
459 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
462 if (!pm->monitor && !pm->monitorUI) {
463 monitor_unload(pm);
464 SetLastError(ERROR_PROC_NOT_FOUND);
465 pm = NULL;
468 cleanup:
469 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
470 pm->refcount++;
471 pm_localport = pm;
473 LeaveCriticalSection(&monitor_handles_cs);
474 if (driver != dllname) heap_free(driver);
475 heap_free(regroot);
476 TRACE("=> %p\n", pm);
477 return pm;
480 /******************************************************************
481 * monitor_loadall [internal]
483 * Load all registered monitors
486 static DWORD monitor_loadall(void)
488 monitor_t * pm;
489 DWORD registered = 0;
490 DWORD loaded = 0;
491 HKEY hmonitors;
492 WCHAR buffer[MAX_PATH];
493 DWORD id = 0;
495 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
496 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
497 NULL, NULL, NULL, NULL, NULL);
499 TRACE("%d monitors registered\n", registered);
501 while (id < registered) {
502 buffer[0] = '\0';
503 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
504 pm = monitor_load(buffer, NULL);
505 if (pm) loaded++;
506 id++;
508 RegCloseKey(hmonitors);
510 TRACE("%d monitors loaded\n", loaded);
511 return loaded;
514 /******************************************************************
515 * Return the number of bytes for an multi_sz string.
516 * The result includes all \0s
517 * (specifically the extra \0, that is needed as multi_sz terminator).
519 static int multi_sz_lenW(const WCHAR *str)
521 const WCHAR *ptr = str;
522 if (!str) return 0;
525 ptr += lstrlenW(ptr) + 1;
526 } while (*ptr);
528 return (ptr - str + 1) * sizeof(WCHAR);
531 /******************************************************************
532 * validate_envW [internal]
534 * validate the user-supplied printing-environment
536 * PARAMS
537 * env [I] PTR to Environment-String or NULL
539 * RETURNS
540 * Success: PTR to printenv_t
541 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
543 * NOTES
544 * An empty string is handled the same way as NULL.
548 static const printenv_t * validate_envW(LPCWSTR env)
550 const printenv_t *result = NULL;
551 unsigned int i;
553 TRACE("(%s)\n", debugstr_w(env));
554 if (env && env[0])
556 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
558 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
560 result = all_printenv[i];
561 break;
564 if (result == NULL) {
565 FIXME("unsupported Environment: %s\n", debugstr_w(env));
566 SetLastError(ERROR_INVALID_ENVIRONMENT);
568 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
570 else
572 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
575 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
576 return result;
579 /*****************************************************************************
580 * enumerate the local monitors (INTERNAL)
582 * returns the needed size (in bytes) for pMonitors
583 * and *lpreturned is set to number of entries returned in pMonitors
585 * Language-Monitors are also installed in the same Registry-Location but
586 * they are filtered in Windows (not returned by EnumMonitors).
587 * We do no filtering to simplify our Code.
590 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
592 HKEY hroot = NULL;
593 HKEY hentry = NULL;
594 LPWSTR ptr;
595 LPMONITOR_INFO_2W mi;
596 WCHAR buffer[MAX_PATH];
597 WCHAR dllname[MAX_PATH];
598 DWORD dllsize;
599 DWORD len;
600 DWORD index = 0;
601 DWORD needed = 0;
602 DWORD numentries;
603 DWORD entrysize;
605 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
607 numentries = *lpreturned; /* this is 0, when we scan the registry */
608 len = entrysize * numentries;
609 ptr = (LPWSTR) &pMonitors[len];
611 numentries = 0;
612 len = sizeof(buffer)/sizeof(buffer[0]);
613 buffer[0] = '\0';
615 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
616 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
617 /* Scan all Monitor-Registry-Keys */
618 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
619 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
620 dllsize = sizeof(dllname);
621 dllname[0] = '\0';
623 /* The Monitor must have a Driver-DLL */
624 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
625 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
626 /* We found a valid DLL for this Monitor. */
627 TRACE("using Driver: %s\n", debugstr_w(dllname));
629 RegCloseKey(hentry);
632 /* Windows returns only Port-Monitors here, but to simplify our code,
633 we do no filtering for Language-Monitors */
634 if (dllname[0]) {
635 numentries++;
636 needed += entrysize;
637 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
638 if (level > 1) {
639 /* we install and return only monitors for "Windows NT x86" */
640 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
641 needed += dllsize;
644 /* required size is calculated. Now fill the user-buffer */
645 if (pMonitors && (cbBuf >= needed)){
646 mi = (LPMONITOR_INFO_2W) pMonitors;
647 pMonitors += entrysize;
649 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
650 mi->pName = ptr;
651 lstrcpyW(ptr, buffer); /* Name of the Monitor */
652 ptr += (len+1); /* len is lstrlenW(monitorname) */
653 if (level > 1) {
654 mi->pEnvironment = ptr;
655 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
656 ptr += (lstrlenW(x86_envnameW)+1);
658 mi->pDLLName = ptr;
659 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
660 ptr += (dllsize / sizeof(WCHAR));
664 index++;
665 len = sizeof(buffer)/sizeof(buffer[0]);
666 buffer[0] = '\0';
668 RegCloseKey(hroot);
670 *lpreturned = numentries;
671 TRACE("need %d byte for %d entries\n", needed, numentries);
672 return needed;
675 /******************************************************************
676 * enumerate the local Ports from all loaded monitors (internal)
678 * returns the needed size (in bytes) for pPorts
679 * and *lpreturned is set to number of entries returned in pPorts
682 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
684 monitor_t * pm;
685 LPWSTR ptr;
686 LPPORT_INFO_2W cache;
687 LPPORT_INFO_2W out;
688 LPBYTE pi_buffer = NULL;
689 DWORD pi_allocated = 0;
690 DWORD pi_needed;
691 DWORD pi_index;
692 DWORD pi_returned;
693 DWORD res;
694 DWORD outindex = 0;
695 DWORD needed;
696 DWORD numentries;
697 DWORD entrysize;
700 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
701 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
703 numentries = *lpreturned; /* this is 0, when we scan the registry */
704 needed = entrysize * numentries;
705 ptr = (LPWSTR) &pPorts[needed];
707 numentries = 0;
708 needed = 0;
710 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
712 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
713 pi_needed = 0;
714 pi_returned = 0;
715 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
716 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
717 /* Do not use heap_realloc (we do not need the old data in the buffer) */
718 heap_free(pi_buffer);
719 pi_buffer = heap_alloc(pi_needed);
720 pi_allocated = (pi_buffer) ? pi_needed : 0;
721 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
723 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
724 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
726 numentries += pi_returned;
727 needed += pi_needed;
729 /* fill the output-buffer (pPorts), if we have one */
730 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
731 pi_index = 0;
732 while (pi_returned > pi_index) {
733 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
734 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
735 out->pPortName = ptr;
736 lstrcpyW(ptr, cache->pPortName);
737 ptr += (lstrlenW(ptr)+1);
738 if (level > 1) {
739 out->pMonitorName = ptr;
740 lstrcpyW(ptr, cache->pMonitorName);
741 ptr += (lstrlenW(ptr)+1);
743 out->pDescription = ptr;
744 lstrcpyW(ptr, cache->pDescription);
745 ptr += (lstrlenW(ptr)+1);
746 out->fPortType = cache->fPortType;
747 out->Reserved = cache->Reserved;
749 pi_index++;
750 outindex++;
755 /* the temporary portinfo-buffer is no longer needed */
756 heap_free(pi_buffer);
758 *lpreturned = numentries;
759 TRACE("need %d byte for %d entries\n", needed, numentries);
760 return needed;
764 /*****************************************************************************
765 * open_driver_reg [internal]
767 * opens the registry for the printer drivers depending on the given input
768 * variable pEnvironment
770 * RETURNS:
771 * Success: the opened hkey
772 * Failure: NULL
774 static HKEY open_driver_reg(LPCWSTR pEnvironment)
776 HKEY retval = NULL;
777 LPWSTR buffer;
778 const printenv_t * env;
780 TRACE("(%s)\n", debugstr_w(pEnvironment));
782 env = validate_envW(pEnvironment);
783 if (!env) return NULL;
785 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
786 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
788 if (buffer) {
789 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
790 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
791 HeapFree(GetProcessHeap(), 0, buffer);
793 return retval;
796 /*****************************************************************************
797 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
799 * Return the PATH for the Printer-Drivers
801 * PARAMS
802 * pName [I] Servername (NT only) or NULL (local Computer)
803 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
804 * Level [I] Structure-Level (must be 1)
805 * pDriverDirectory [O] PTR to Buffer that receives the Result
806 * cbBuf [I] Size of Buffer at pDriverDirectory
807 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
808 * required for pDriverDirectory
810 * RETURNS
811 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
812 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
813 * if cbBuf is too small
815 * Native Values returned in pDriverDirectory on Success:
816 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
817 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
818 *| win9x(Windows 4.0): "%winsysdir%"
820 * "%winsysdir%" is the Value from GetSystemDirectoryW()
823 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
824 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
826 DWORD needed;
827 const printenv_t * env;
829 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
830 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
832 if (pName != NULL && pName[0]) {
833 FIXME("server %s not supported\n", debugstr_w(pName));
834 SetLastError(ERROR_INVALID_PARAMETER);
835 return FALSE;
838 env = validate_envW(pEnvironment);
839 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
842 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
843 needed = GetSystemDirectoryW(NULL, 0);
844 /* add the Size for the Subdirectories */
845 needed += lstrlenW(spooldriversW);
846 needed += lstrlenW(env->subdir);
847 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
849 *pcbNeeded = needed;
851 if (needed > cbBuf) {
852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
853 return FALSE;
856 if (pDriverDirectory == NULL) {
857 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
858 SetLastError(ERROR_INVALID_USER_BUFFER);
859 return FALSE;
862 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
863 /* add the Subdirectories */
864 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
865 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
867 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
868 return TRUE;
871 /******************************************************************
872 * driver_load [internal]
874 * load a driver user interface dll
876 * On failure, NULL is returned
880 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
882 WCHAR fullname[MAX_PATH];
883 HMODULE hui;
884 DWORD len;
886 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
888 /* build the driverdir */
889 len = sizeof(fullname) -
890 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
892 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
893 (LPBYTE) fullname, len, &len)) {
894 /* Should never Fail */
895 SetLastError(ERROR_BUFFER_OVERFLOW);
896 return NULL;
899 lstrcatW(fullname, env->versionsubdir);
900 lstrcatW(fullname, backslashW);
901 lstrcatW(fullname, dllname);
903 hui = LoadLibraryW(fullname);
904 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
906 return hui;
909 /******************************************************************************
910 * myAddPrinterDriverEx [internal]
912 * Install a Printer Driver with the Option to upgrade / downgrade the Files
913 * and a special mode with lazy error checking.
916 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
918 static const WCHAR emptyW[1];
919 const printenv_t *env;
920 apd_data_t apd;
921 DRIVER_INFO_8W di;
922 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
923 HMODULE hui;
924 LPWSTR ptr;
925 HKEY hroot;
926 HKEY hdrv;
927 DWORD disposition;
928 DWORD len;
929 LONG lres;
930 BOOL res;
932 /* we need to set all entries in the Registry, independent from the Level of
933 DRIVER_INFO, that the caller supplied */
935 ZeroMemory(&di, sizeof(di));
936 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
937 memcpy(&di, pDriverInfo, di_sizeof[level]);
940 /* dump the most used infos */
941 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
942 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
943 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
944 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
945 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
946 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
947 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
948 /* dump only the first of the additional Files */
949 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
952 /* check environment */
953 env = validate_envW(di.pEnvironment);
954 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
956 /* fill the copy-data / get the driverdir */
957 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
958 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
959 (LPBYTE) apd.src, len, &len)) {
960 /* Should never Fail */
961 return FALSE;
963 memcpy(apd.dst, apd.src, len);
964 lstrcatW(apd.src, backslashW);
965 apd.srclen = lstrlenW(apd.src);
966 lstrcatW(apd.dst, env->versionsubdir);
967 lstrcatW(apd.dst, backslashW);
968 apd.dstlen = lstrlenW(apd.dst);
969 apd.copyflags = dwFileCopyFlags;
970 apd.lazy = lazy;
971 CreateDirectoryW(apd.src, NULL);
972 CreateDirectoryW(apd.dst, NULL);
974 hroot = open_driver_reg(env->envname);
975 if (!hroot) {
976 ERR("Can't create Drivers key\n");
977 return FALSE;
980 /* Fill the Registry for the Driver */
981 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
982 KEY_WRITE | KEY_QUERY_VALUE, NULL,
983 &hdrv, &disposition)) != ERROR_SUCCESS) {
985 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
986 RegCloseKey(hroot);
987 SetLastError(lres);
988 return FALSE;
990 RegCloseKey(hroot);
992 if (disposition == REG_OPENED_EXISTING_KEY) {
993 TRACE("driver %s already installed\n", debugstr_w(di.pName));
994 RegCloseKey(hdrv);
995 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
996 return FALSE;
999 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1000 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1001 sizeof(DWORD));
1003 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1004 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1005 apd_copyfile(di.pDriverPath, &apd);
1007 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1008 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1009 apd_copyfile(di.pDataFile, &apd);
1011 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1012 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1013 apd_copyfile(di.pConfigFile, &apd);
1015 /* settings for level 3 */
1016 if (di.pHelpFile)
1017 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1018 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1019 else
1020 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1021 apd_copyfile(di.pHelpFile, &apd);
1024 ptr = di.pDependentFiles;
1025 if (ptr)
1026 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1027 multi_sz_lenW(di.pDependentFiles));
1028 else
1029 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1030 while ((ptr != NULL) && (ptr[0])) {
1031 if (apd_copyfile(ptr, &apd)) {
1032 ptr += lstrlenW(ptr) + 1;
1034 else
1036 WARN("Failed to copy %s\n", debugstr_w(ptr));
1037 ptr = NULL;
1040 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1041 if (di.pMonitorName)
1042 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1043 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1044 else
1045 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1047 if (di.pDefaultDataType)
1048 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1049 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1050 else
1051 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1053 /* settings for level 4 */
1054 if (di.pszzPreviousNames)
1055 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1056 multi_sz_lenW(di.pszzPreviousNames));
1057 else
1058 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1060 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1062 RegCloseKey(hdrv);
1063 hui = driver_load(env, di.pConfigFile);
1064 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1065 if (hui && pDrvDriverEvent) {
1067 /* Support for DrvDriverEvent is optional */
1068 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1069 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1070 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1071 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1073 FreeLibrary(hui);
1075 TRACE("=> TRUE with %u\n", GetLastError());
1076 return TRUE;
1080 /******************************************************************************
1081 * fpAddMonitor [exported through PRINTPROVIDOR]
1083 * Install a Printmonitor
1085 * PARAMS
1086 * pName [I] Servername or NULL (local Computer)
1087 * Level [I] Structure-Level (Must be 2)
1088 * pMonitors [I] PTR to MONITOR_INFO_2
1090 * RETURNS
1091 * Success: TRUE
1092 * Failure: FALSE
1094 * NOTES
1095 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1098 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1100 monitor_t * pm = NULL;
1101 LPMONITOR_INFO_2W mi2w;
1102 HKEY hroot = NULL;
1103 HKEY hentry = NULL;
1104 DWORD disposition;
1105 BOOL res = FALSE;
1107 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1108 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1109 debugstr_w(mi2w ? mi2w->pName : NULL),
1110 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1111 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1113 if (copy_servername_from_name(pName, NULL)) {
1114 FIXME("server %s not supported\n", debugstr_w(pName));
1115 SetLastError(ERROR_ACCESS_DENIED);
1116 return FALSE;
1119 if (!mi2w->pName || (! mi2w->pName[0])) {
1120 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1121 SetLastError(ERROR_INVALID_PARAMETER);
1122 return FALSE;
1124 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1125 WARN("Environment %s requested (we support only %s)\n",
1126 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1127 SetLastError(ERROR_INVALID_ENVIRONMENT);
1128 return FALSE;
1131 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1132 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1133 SetLastError(ERROR_INVALID_PARAMETER);
1134 return FALSE;
1137 /* Load and initialize the monitor. SetLastError() is called on failure */
1138 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1139 return FALSE;
1141 monitor_unload(pm);
1143 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1144 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1145 return FALSE;
1148 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1149 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1150 &disposition) == ERROR_SUCCESS) {
1152 /* Some installers set options for the port before calling AddMonitor.
1153 We query the "Driver" entry to verify that the monitor is installed,
1154 before we return an error.
1155 When a user installs two print monitors at the same time with the
1156 same name, a race condition is possible but silently ignored. */
1158 DWORD namesize = 0;
1160 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1161 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1162 &namesize) == ERROR_SUCCESS)) {
1163 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1164 /* 9x use ERROR_ALREADY_EXISTS */
1165 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1167 else
1169 INT len;
1170 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1171 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1172 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1174 RegCloseKey(hentry);
1177 RegCloseKey(hroot);
1178 return (res);
1181 /******************************************************************************
1182 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1184 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1186 * PARAMS
1187 * pName [I] Servername or NULL (local Computer)
1188 * level [I] Level for the supplied DRIVER_INFO_*W struct
1189 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1190 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1192 * RESULTS
1193 * Success: TRUE
1194 * Failure: FALSE
1197 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1199 LONG lres;
1201 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1202 lres = copy_servername_from_name(pName, NULL);
1203 if (lres) {
1204 FIXME("server %s not supported\n", debugstr_w(pName));
1205 SetLastError(ERROR_ACCESS_DENIED);
1206 return FALSE;
1209 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1210 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1213 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1215 /******************************************************************
1216 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1218 * Delete a specific Printmonitor from a Printing-Environment
1220 * PARAMS
1221 * pName [I] Servername or NULL (local Computer)
1222 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1223 * pMonitorName [I] Name of the Monitor, that should be deleted
1225 * RETURNS
1226 * Success: TRUE
1227 * Failure: FALSE
1229 * NOTES
1230 * pEnvironment is ignored in Windows for the local Computer.
1234 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1236 HKEY hroot = NULL;
1237 LONG lres;
1239 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1240 debugstr_w(pMonitorName));
1242 lres = copy_servername_from_name(pName, NULL);
1243 if (lres) {
1244 FIXME("server %s not supported\n", debugstr_w(pName));
1245 SetLastError(ERROR_INVALID_NAME);
1246 return FALSE;
1249 /* pEnvironment is ignored in Windows for the local Computer */
1250 if (!pMonitorName || !pMonitorName[0]) {
1251 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1252 SetLastError(ERROR_INVALID_PARAMETER);
1253 return FALSE;
1256 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1257 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1258 return FALSE;
1261 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1262 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1263 RegCloseKey(hroot);
1264 return TRUE;
1267 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1268 RegCloseKey(hroot);
1270 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1271 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1272 return FALSE;
1275 /*****************************************************************************
1276 * fpEnumMonitors [exported through PRINTPROVIDOR]
1278 * Enumerate available Port-Monitors
1280 * PARAMS
1281 * pName [I] Servername or NULL (local Computer)
1282 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1283 * pMonitors [O] PTR to Buffer that receives the Result
1284 * cbBuf [I] Size of Buffer at pMonitors
1285 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1286 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1288 * RETURNS
1289 * Success: TRUE
1290 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1292 * NOTES
1293 * Windows reads the Registry once and cache the Results.
1296 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1297 LPDWORD pcbNeeded, LPDWORD pcReturned)
1299 DWORD numentries = 0;
1300 DWORD needed = 0;
1301 LONG lres;
1302 BOOL res = FALSE;
1304 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1305 cbBuf, pcbNeeded, pcReturned);
1307 lres = copy_servername_from_name(pName, NULL);
1308 if (lres) {
1309 FIXME("server %s not supported\n", debugstr_w(pName));
1310 SetLastError(ERROR_INVALID_NAME);
1311 goto em_cleanup;
1314 if (!Level || (Level > 2)) {
1315 WARN("level (%d) is ignored in win9x\n", Level);
1316 SetLastError(ERROR_INVALID_LEVEL);
1317 return FALSE;
1320 /* Scan all Monitor-Keys */
1321 numentries = 0;
1322 needed = get_local_monitors(Level, NULL, 0, &numentries);
1324 /* we calculated the needed buffersize. now do more error-checks */
1325 if (cbBuf < needed) {
1326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1327 goto em_cleanup;
1330 /* fill the Buffer with the Monitor-Keys */
1331 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1332 res = TRUE;
1334 em_cleanup:
1335 if (pcbNeeded) *pcbNeeded = needed;
1336 if (pcReturned) *pcReturned = numentries;
1338 TRACE("returning %d with %d (%d byte for %d entries)\n",
1339 res, GetLastError(), needed, numentries);
1341 return (res);
1344 /******************************************************************************
1345 * fpEnumPorts [exported through PRINTPROVIDOR]
1347 * Enumerate available Ports
1349 * PARAMS
1350 * pName [I] Servername or NULL (local Computer)
1351 * Level [I] Structure-Level (1 or 2)
1352 * pPorts [O] PTR to Buffer that receives the Result
1353 * cbBuf [I] Size of Buffer at pPorts
1354 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1355 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1357 * RETURNS
1358 * Success: TRUE
1359 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1362 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1363 LPDWORD pcbNeeded, LPDWORD pcReturned)
1365 DWORD needed = 0;
1366 DWORD numentries = 0;
1367 LONG lres;
1368 BOOL res = FALSE;
1370 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1371 cbBuf, pcbNeeded, pcReturned);
1373 lres = copy_servername_from_name(pName, NULL);
1374 if (lres) {
1375 FIXME("server %s not supported\n", debugstr_w(pName));
1376 SetLastError(ERROR_INVALID_NAME);
1377 goto emP_cleanup;
1380 if (!Level || (Level > 2)) {
1381 SetLastError(ERROR_INVALID_LEVEL);
1382 goto emP_cleanup;
1385 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1386 SetLastError(RPC_X_NULL_REF_POINTER);
1387 goto emP_cleanup;
1390 EnterCriticalSection(&monitor_handles_cs);
1391 monitor_loadall();
1393 /* Scan all local Ports */
1394 numentries = 0;
1395 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1397 /* we calculated the needed buffersize. now do the error-checks */
1398 if (cbBuf < needed) {
1399 monitor_unloadall();
1400 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1401 goto emP_cleanup_cs;
1403 else if (!pPorts || !pcReturned) {
1404 monitor_unloadall();
1405 SetLastError(RPC_X_NULL_REF_POINTER);
1406 goto emP_cleanup_cs;
1409 /* Fill the Buffer */
1410 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1411 res = TRUE;
1412 monitor_unloadall();
1414 emP_cleanup_cs:
1415 LeaveCriticalSection(&monitor_handles_cs);
1417 emP_cleanup:
1418 if (pcbNeeded) *pcbNeeded = needed;
1419 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1421 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1422 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1424 return (res);
1427 /*****************************************************
1428 * setup_provider [internal]
1430 void setup_provider(void)
1432 static const PRINTPROVIDOR backend = {
1433 NULL, /* fpOpenPrinter */
1434 NULL, /* fpSetJob */
1435 NULL, /* fpGetJob */
1436 NULL, /* fpEnumJobs */
1437 NULL, /* fpAddPrinter */
1438 NULL, /* fpDeletePrinter */
1439 NULL, /* fpSetPrinter */
1440 NULL, /* fpGetPrinter */
1441 NULL, /* fpEnumPrinters */
1442 NULL, /* fpAddPrinterDriver */
1443 NULL, /* fpEnumPrinterDrivers */
1444 NULL, /* fpGetPrinterDriver */
1445 fpGetPrinterDriverDirectory,
1446 NULL, /* fpDeletePrinterDriver */
1447 NULL, /* fpAddPrintProcessor */
1448 NULL, /* fpEnumPrintProcessors */
1449 NULL, /* fpGetPrintProcessorDirectory */
1450 NULL, /* fpDeletePrintProcessor */
1451 NULL, /* fpEnumPrintProcessorDatatypes */
1452 NULL, /* fpStartDocPrinter */
1453 NULL, /* fpStartPagePrinter */
1454 NULL, /* fpWritePrinter */
1455 NULL, /* fpEndPagePrinter */
1456 NULL, /* fpAbortPrinter */
1457 NULL, /* fpReadPrinter */
1458 NULL, /* fpEndDocPrinter */
1459 NULL, /* fpAddJob */
1460 NULL, /* fpScheduleJob */
1461 NULL, /* fpGetPrinterData */
1462 NULL, /* fpSetPrinterData */
1463 NULL, /* fpWaitForPrinterChange */
1464 NULL, /* fpClosePrinter */
1465 NULL, /* fpAddForm */
1466 NULL, /* fpDeleteForm */
1467 NULL, /* fpGetForm */
1468 NULL, /* fpSetForm */
1469 NULL, /* fpEnumForms */
1470 fpEnumMonitors,
1471 fpEnumPorts,
1472 NULL, /* fpAddPort */
1473 NULL, /* fpConfigurePort */
1474 NULL, /* fpDeletePort */
1475 NULL, /* fpCreatePrinterIC */
1476 NULL, /* fpPlayGdiScriptOnPrinterIC */
1477 NULL, /* fpDeletePrinterIC */
1478 NULL, /* fpAddPrinterConnection */
1479 NULL, /* fpDeletePrinterConnection */
1480 NULL, /* fpPrinterMessageBox */
1481 fpAddMonitor,
1482 fpDeleteMonitor,
1483 NULL, /* fpResetPrinter */
1484 NULL, /* fpGetPrinterDriverEx */
1485 NULL, /* fpFindFirstPrinterChangeNotification */
1486 NULL, /* fpFindClosePrinterChangeNotification */
1487 NULL, /* fpAddPortEx */
1488 NULL, /* fpShutDown */
1489 NULL, /* fpRefreshPrinterChangeNotification */
1490 NULL, /* fpOpenPrinterEx */
1491 NULL, /* fpAddPrinterEx */
1492 NULL, /* fpSetPort */
1493 NULL, /* fpEnumPrinterData */
1494 NULL, /* fpDeletePrinterData */
1495 NULL, /* fpClusterSplOpen */
1496 NULL, /* fpClusterSplClose */
1497 NULL, /* fpClusterSplIsAlive */
1498 NULL, /* fpSetPrinterDataEx */
1499 NULL, /* fpGetPrinterDataEx */
1500 NULL, /* fpEnumPrinterDataEx */
1501 NULL, /* fpEnumPrinterKey */
1502 NULL, /* fpDeletePrinterDataEx */
1503 NULL, /* fpDeletePrinterKey */
1504 NULL, /* fpSeekPrinter */
1505 NULL, /* fpDeletePrinterDriverEx */
1506 NULL, /* fpAddPerMachineConnection */
1507 NULL, /* fpDeletePerMachineConnection */
1508 NULL, /* fpEnumPerMachineConnections */
1509 NULL, /* fpXcvData */
1510 fpAddPrinterDriverEx,
1511 NULL, /* fpSplReadPrinter */
1512 NULL, /* fpDriverUnloadComplete */
1513 NULL, /* fpGetSpoolFileInfo */
1514 NULL, /* fpCommitSpoolData */
1515 NULL, /* fpCloseSpoolFileHandle */
1516 NULL, /* fpFlushPrinter */
1517 NULL, /* fpSendRecvBidiData */
1518 NULL /* fpAddDriverCatalog */
1520 pprovider = &backend;
1524 /*****************************************************
1525 * InitializePrintProvidor (localspl.@)
1527 * Initialize the Printprovider
1529 * PARAMS
1530 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1531 * cbPrintProvidor [I] Size of Buffer in Bytes
1532 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1534 * RETURNS
1535 * Success: TRUE and pPrintProvidor filled
1536 * Failure: FALSE
1538 * NOTES
1539 * The RegistryPath should be:
1540 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1541 * but this Parameter is ignored in "localspl.dll".
1545 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1546 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1549 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1550 memcpy(pPrintProvidor, pprovider,
1551 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1553 return TRUE;