d3dxof: Remove limitation on data buffer size.
[wine/multimedia.git] / dlls / localspl / provider.c
blobf308e36d7e93dfd9f0dbbf75bc794f58b5dee254
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 */
255 if (serverlen == 0) return 0;
257 TRACE("found %s\n", debugstr_wn(server, serverlen));
259 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
261 if (target) {
262 memcpy(target, server, serverlen * sizeof(WCHAR));
263 target[serverlen] = '\0';
266 len = sizeof(buffer) / sizeof(buffer[0]);
267 if (GetComputerNameW(buffer, &len)) {
268 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
269 /* The requested Servername is our computername */
270 return 0;
273 return serverlen;
276 /******************************************************************
277 * monitor_unload [internal]
279 * release a printmonitor and unload it from memory, when needed
282 static void monitor_unload(monitor_t * pm)
284 if (pm == NULL) return;
285 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
287 EnterCriticalSection(&monitor_handles_cs);
289 if (pm->refcount) pm->refcount--;
291 if (pm->refcount == 0) {
292 list_remove(&pm->entry);
293 FreeLibrary(pm->hdll);
294 heap_free(pm->name);
295 heap_free(pm->dllname);
296 heap_free(pm);
298 LeaveCriticalSection(&monitor_handles_cs);
301 /******************************************************************
302 * monitor_unloadall [internal]
304 * release all printmonitors and unload them from memory, when needed
308 static void monitor_unloadall(void)
310 monitor_t * pm;
311 monitor_t * next;
313 EnterCriticalSection(&monitor_handles_cs);
314 /* iterate through the list, with safety against removal */
315 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
317 monitor_unload(pm);
319 LeaveCriticalSection(&monitor_handles_cs);
322 /******************************************************************
323 * monitor_load [internal]
325 * load a printmonitor, get the dllname from the registry, when needed
326 * initialize the monitor and dump found function-pointers
328 * On failure, SetLastError() is called and NULL is returned
331 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
333 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
334 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
335 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
336 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
337 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
339 monitor_t * pm = NULL;
340 monitor_t * cursor;
341 LPWSTR regroot = NULL;
342 LPWSTR driver = dllname;
344 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
345 /* Is the Monitor already loaded? */
346 EnterCriticalSection(&monitor_handles_cs);
348 if (name) {
349 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
351 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
352 pm = cursor;
353 break;
358 if (pm == NULL) {
359 pm = heap_alloc_zero(sizeof(monitor_t));
360 if (pm == NULL) goto cleanup;
361 list_add_tail(&monitor_handles, &pm->entry);
363 pm->refcount++;
365 if (pm->name == NULL) {
366 /* Load the monitor */
367 LPMONITOREX pmonitorEx;
368 DWORD len;
370 if (name) {
371 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
372 regroot = heap_alloc(len * sizeof(WCHAR));
375 if (regroot) {
376 lstrcpyW(regroot, monitorsW);
377 lstrcatW(regroot, name);
378 /* Get the Driver from the Registry */
379 if (driver == NULL) {
380 HKEY hroot;
381 DWORD namesize;
382 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
383 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
384 &namesize) == ERROR_SUCCESS) {
385 driver = heap_alloc(namesize);
386 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
388 RegCloseKey(hroot);
393 pm->name = strdupW(name);
394 pm->dllname = strdupW(driver);
396 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
397 monitor_unload(pm);
398 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
399 pm = NULL;
400 goto cleanup;
403 pm->hdll = LoadLibraryW(driver);
404 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
406 if (pm->hdll == NULL) {
407 monitor_unload(pm);
408 SetLastError(ERROR_MOD_NOT_FOUND);
409 pm = NULL;
410 goto cleanup;
413 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
414 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
415 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
416 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
417 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
420 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
421 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
422 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
423 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
424 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
426 if (pInitializePrintMonitorUI != NULL) {
427 pm->monitorUI = pInitializePrintMonitorUI();
428 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
429 if (pm->monitorUI) {
430 TRACE("0x%08x: dwMonitorSize (%d)\n",
431 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
436 if (pInitializePrintMonitor && regroot) {
437 pmonitorEx = pInitializePrintMonitor(regroot);
438 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
439 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
441 if (pmonitorEx) {
442 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
443 pm->monitor = &(pmonitorEx->Monitor);
447 if (pm->monitor) {
448 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
452 if (!pm->monitor && regroot) {
453 if (pInitializePrintMonitor2 != NULL) {
454 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
456 if (pInitializeMonitorEx != NULL) {
457 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
459 if (pInitializeMonitor != NULL) {
460 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
463 if (!pm->monitor && !pm->monitorUI) {
464 monitor_unload(pm);
465 SetLastError(ERROR_PROC_NOT_FOUND);
466 pm = NULL;
469 cleanup:
470 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
471 pm->refcount++;
472 pm_localport = pm;
474 LeaveCriticalSection(&monitor_handles_cs);
475 if (driver != dllname) heap_free(driver);
476 heap_free(regroot);
477 TRACE("=> %p\n", pm);
478 return pm;
481 /******************************************************************
482 * monitor_loadall [internal]
484 * Load all registered monitors
487 static DWORD monitor_loadall(void)
489 monitor_t * pm;
490 DWORD registered = 0;
491 DWORD loaded = 0;
492 HKEY hmonitors;
493 WCHAR buffer[MAX_PATH];
494 DWORD id = 0;
496 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
497 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
498 NULL, NULL, NULL, NULL, NULL);
500 TRACE("%d monitors registered\n", registered);
502 while (id < registered) {
503 buffer[0] = '\0';
504 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
505 pm = monitor_load(buffer, NULL);
506 if (pm) loaded++;
507 id++;
509 RegCloseKey(hmonitors);
511 TRACE("%d monitors loaded\n", loaded);
512 return loaded;
515 /******************************************************************
516 * Return the number of bytes for an multi_sz string.
517 * The result includes all \0s
518 * (specifically the extra \0, that is needed as multi_sz terminator).
520 static int multi_sz_lenW(const WCHAR *str)
522 const WCHAR *ptr = str;
523 if (!str) return 0;
526 ptr += lstrlenW(ptr) + 1;
527 } while (*ptr);
529 return (ptr - str + 1) * sizeof(WCHAR);
532 /******************************************************************
533 * validate_envW [internal]
535 * validate the user-supplied printing-environment
537 * PARAMS
538 * env [I] PTR to Environment-String or NULL
540 * RETURNS
541 * Success: PTR to printenv_t
542 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
544 * NOTES
545 * An empty string is handled the same way as NULL.
549 static const printenv_t * validate_envW(LPCWSTR env)
551 const printenv_t *result = NULL;
552 unsigned int i;
554 TRACE("(%s)\n", debugstr_w(env));
555 if (env && env[0])
557 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
559 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
561 result = all_printenv[i];
562 break;
565 if (result == NULL) {
566 FIXME("unsupported Environment: %s\n", debugstr_w(env));
567 SetLastError(ERROR_INVALID_ENVIRONMENT);
569 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
571 else
573 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
576 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
577 return result;
580 /*****************************************************************************
581 * enumerate the local monitors (INTERNAL)
583 * returns the needed size (in bytes) for pMonitors
584 * and *lpreturned is set to number of entries returned in pMonitors
586 * Language-Monitors are also installed in the same Registry-Location but
587 * they are filtered in Windows (not returned by EnumMonitors).
588 * We do no filtering to simplify our Code.
591 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
593 HKEY hroot = NULL;
594 HKEY hentry = NULL;
595 LPWSTR ptr;
596 LPMONITOR_INFO_2W mi;
597 WCHAR buffer[MAX_PATH];
598 WCHAR dllname[MAX_PATH];
599 DWORD dllsize;
600 DWORD len;
601 DWORD index = 0;
602 DWORD needed = 0;
603 DWORD numentries;
604 DWORD entrysize;
606 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
608 numentries = *lpreturned; /* this is 0, when we scan the registry */
609 len = entrysize * numentries;
610 ptr = (LPWSTR) &pMonitors[len];
612 numentries = 0;
613 len = sizeof(buffer)/sizeof(buffer[0]);
614 buffer[0] = '\0';
616 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
617 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
618 /* Scan all Monitor-Registry-Keys */
619 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
620 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
621 dllsize = sizeof(dllname);
622 dllname[0] = '\0';
624 /* The Monitor must have a Driver-DLL */
625 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
626 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
627 /* We found a valid DLL for this Monitor. */
628 TRACE("using Driver: %s\n", debugstr_w(dllname));
630 RegCloseKey(hentry);
633 /* Windows returns only Port-Monitors here, but to simplify our code,
634 we do no filtering for Language-Monitors */
635 if (dllname[0]) {
636 numentries++;
637 needed += entrysize;
638 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
639 if (level > 1) {
640 /* we install and return only monitors for "Windows NT x86" */
641 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
642 needed += dllsize;
645 /* required size is calculated. Now fill the user-buffer */
646 if (pMonitors && (cbBuf >= needed)){
647 mi = (LPMONITOR_INFO_2W) pMonitors;
648 pMonitors += entrysize;
650 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
651 mi->pName = ptr;
652 lstrcpyW(ptr, buffer); /* Name of the Monitor */
653 ptr += (len+1); /* len is lstrlenW(monitorname) */
654 if (level > 1) {
655 mi->pEnvironment = ptr;
656 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
657 ptr += (lstrlenW(x86_envnameW)+1);
659 mi->pDLLName = ptr;
660 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
661 ptr += (dllsize / sizeof(WCHAR));
665 index++;
666 len = sizeof(buffer)/sizeof(buffer[0]);
667 buffer[0] = '\0';
669 RegCloseKey(hroot);
671 *lpreturned = numentries;
672 TRACE("need %d byte for %d entries\n", needed, numentries);
673 return needed;
676 /******************************************************************
677 * enumerate the local Ports from all loaded monitors (internal)
679 * returns the needed size (in bytes) for pPorts
680 * and *lpreturned is set to number of entries returned in pPorts
683 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
685 monitor_t * pm;
686 LPWSTR ptr;
687 LPPORT_INFO_2W cache;
688 LPPORT_INFO_2W out;
689 LPBYTE pi_buffer = NULL;
690 DWORD pi_allocated = 0;
691 DWORD pi_needed;
692 DWORD pi_index;
693 DWORD pi_returned;
694 DWORD res;
695 DWORD outindex = 0;
696 DWORD needed;
697 DWORD numentries;
698 DWORD entrysize;
701 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
702 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
704 numentries = *lpreturned; /* this is 0, when we scan the registry */
705 needed = entrysize * numentries;
706 ptr = (LPWSTR) &pPorts[needed];
708 numentries = 0;
709 needed = 0;
711 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
713 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
714 pi_needed = 0;
715 pi_returned = 0;
716 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
717 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
718 /* Do not use heap_realloc (we do not need the old data in the buffer) */
719 heap_free(pi_buffer);
720 pi_buffer = heap_alloc(pi_needed);
721 pi_allocated = (pi_buffer) ? pi_needed : 0;
722 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
724 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
725 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
727 numentries += pi_returned;
728 needed += pi_needed;
730 /* fill the output-buffer (pPorts), if we have one */
731 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
732 pi_index = 0;
733 while (pi_returned > pi_index) {
734 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
735 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
736 out->pPortName = ptr;
737 lstrcpyW(ptr, cache->pPortName);
738 ptr += (lstrlenW(ptr)+1);
739 if (level > 1) {
740 out->pMonitorName = ptr;
741 lstrcpyW(ptr, cache->pMonitorName);
742 ptr += (lstrlenW(ptr)+1);
744 out->pDescription = ptr;
745 lstrcpyW(ptr, cache->pDescription);
746 ptr += (lstrlenW(ptr)+1);
747 out->fPortType = cache->fPortType;
748 out->Reserved = cache->Reserved;
750 pi_index++;
751 outindex++;
756 /* the temporary portinfo-buffer is no longer needed */
757 heap_free(pi_buffer);
759 *lpreturned = numentries;
760 TRACE("need %d byte for %d entries\n", needed, numentries);
761 return needed;
765 /*****************************************************************************
766 * open_driver_reg [internal]
768 * opens the registry for the printer drivers depending on the given input
769 * variable pEnvironment
771 * RETURNS:
772 * Success: the opened hkey
773 * Failure: NULL
775 static HKEY open_driver_reg(LPCWSTR pEnvironment)
777 HKEY retval = NULL;
778 LPWSTR buffer;
779 const printenv_t * env;
781 TRACE("(%s)\n", debugstr_w(pEnvironment));
783 env = validate_envW(pEnvironment);
784 if (!env) return NULL;
786 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
787 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
789 if (buffer) {
790 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
791 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
792 HeapFree(GetProcessHeap(), 0, buffer);
794 return retval;
797 /*****************************************************************************
798 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
800 * Return the PATH for the Printer-Drivers
802 * PARAMS
803 * pName [I] Servername (NT only) or NULL (local Computer)
804 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
805 * Level [I] Structure-Level (must be 1)
806 * pDriverDirectory [O] PTR to Buffer that receives the Result
807 * cbBuf [I] Size of Buffer at pDriverDirectory
808 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
809 * required for pDriverDirectory
811 * RETURNS
812 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
813 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
814 * if cbBuf is too small
816 * Native Values returned in pDriverDirectory on Success:
817 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
818 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
819 *| win9x(Windows 4.0): "%winsysdir%"
821 * "%winsysdir%" is the Value from GetSystemDirectoryW()
824 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
825 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
827 DWORD needed;
828 const printenv_t * env;
830 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
831 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
833 if (pName != NULL && pName[0]) {
834 FIXME("server %s not supported\n", debugstr_w(pName));
835 SetLastError(ERROR_INVALID_PARAMETER);
836 return FALSE;
839 env = validate_envW(pEnvironment);
840 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
843 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
844 needed = GetSystemDirectoryW(NULL, 0);
845 /* add the Size for the Subdirectories */
846 needed += lstrlenW(spooldriversW);
847 needed += lstrlenW(env->subdir);
848 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
850 *pcbNeeded = needed;
852 if (needed > cbBuf) {
853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
854 return FALSE;
857 if (pDriverDirectory == NULL) {
858 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
859 SetLastError(ERROR_INVALID_USER_BUFFER);
860 return FALSE;
863 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
864 /* add the Subdirectories */
865 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
866 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
868 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
869 return TRUE;
872 /******************************************************************
873 * driver_load [internal]
875 * load a driver user interface dll
877 * On failure, NULL is returned
881 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
883 WCHAR fullname[MAX_PATH];
884 HMODULE hui;
885 DWORD len;
887 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
889 /* build the driverdir */
890 len = sizeof(fullname) -
891 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
893 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
894 (LPBYTE) fullname, len, &len)) {
895 /* Should never Fail */
896 SetLastError(ERROR_BUFFER_OVERFLOW);
897 return NULL;
900 lstrcatW(fullname, env->versionsubdir);
901 lstrcatW(fullname, backslashW);
902 lstrcatW(fullname, dllname);
904 hui = LoadLibraryW(fullname);
905 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
907 return hui;
910 /******************************************************************************
911 * myAddPrinterDriverEx [internal]
913 * Install a Printer Driver with the Option to upgrade / downgrade the Files
914 * and a special mode with lazy error checking.
917 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
919 static const WCHAR emptyW[1];
920 const printenv_t *env;
921 apd_data_t apd;
922 DRIVER_INFO_8W di;
923 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
924 HMODULE hui;
925 LPWSTR ptr;
926 HKEY hroot;
927 HKEY hdrv;
928 DWORD disposition;
929 DWORD len;
930 LONG lres;
931 BOOL res;
933 /* we need to set all entries in the Registry, independent from the Level of
934 DRIVER_INFO, that the caller supplied */
936 ZeroMemory(&di, sizeof(di));
937 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
938 memcpy(&di, pDriverInfo, di_sizeof[level]);
941 /* dump the most used infos */
942 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
943 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
944 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
945 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
946 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
947 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
948 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
949 /* dump only the first of the additional Files */
950 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
953 /* check environment */
954 env = validate_envW(di.pEnvironment);
955 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
957 /* fill the copy-data / get the driverdir */
958 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
959 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
960 (LPBYTE) apd.src, len, &len)) {
961 /* Should never Fail */
962 return FALSE;
964 memcpy(apd.dst, apd.src, len);
965 lstrcatW(apd.src, backslashW);
966 apd.srclen = lstrlenW(apd.src);
967 lstrcatW(apd.dst, env->versionsubdir);
968 lstrcatW(apd.dst, backslashW);
969 apd.dstlen = lstrlenW(apd.dst);
970 apd.copyflags = dwFileCopyFlags;
971 apd.lazy = lazy;
972 CreateDirectoryW(apd.src, NULL);
973 CreateDirectoryW(apd.dst, NULL);
975 hroot = open_driver_reg(env->envname);
976 if (!hroot) {
977 ERR("Can't create Drivers key\n");
978 return FALSE;
981 /* Fill the Registry for the Driver */
982 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
983 KEY_WRITE | KEY_QUERY_VALUE, NULL,
984 &hdrv, &disposition)) != ERROR_SUCCESS) {
986 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
987 RegCloseKey(hroot);
988 SetLastError(lres);
989 return FALSE;
991 RegCloseKey(hroot);
993 if (disposition == REG_OPENED_EXISTING_KEY) {
994 TRACE("driver %s already installed\n", debugstr_w(di.pName));
995 RegCloseKey(hdrv);
996 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
997 return FALSE;
1000 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1001 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1002 sizeof(DWORD));
1004 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1005 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1006 apd_copyfile(di.pDriverPath, &apd);
1008 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1009 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1010 apd_copyfile(di.pDataFile, &apd);
1012 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1013 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1014 apd_copyfile(di.pConfigFile, &apd);
1016 /* settings for level 3 */
1017 if (di.pHelpFile)
1018 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1019 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1020 else
1021 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1022 apd_copyfile(di.pHelpFile, &apd);
1025 ptr = di.pDependentFiles;
1026 if (ptr)
1027 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1028 multi_sz_lenW(di.pDependentFiles));
1029 else
1030 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1031 while ((ptr != NULL) && (ptr[0])) {
1032 if (apd_copyfile(ptr, &apd)) {
1033 ptr += lstrlenW(ptr) + 1;
1035 else
1037 WARN("Failed to copy %s\n", debugstr_w(ptr));
1038 ptr = NULL;
1041 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1042 if (di.pMonitorName)
1043 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1044 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1045 else
1046 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1048 if (di.pDefaultDataType)
1049 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1050 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1051 else
1052 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1054 /* settings for level 4 */
1055 if (di.pszzPreviousNames)
1056 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1057 multi_sz_lenW(di.pszzPreviousNames));
1058 else
1059 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1061 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1063 RegCloseKey(hdrv);
1064 hui = driver_load(env, di.pConfigFile);
1065 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1066 if (hui && pDrvDriverEvent) {
1068 /* Support for DrvDriverEvent is optional */
1069 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1070 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1071 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1072 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1074 FreeLibrary(hui);
1076 TRACE("=> TRUE with %u\n", GetLastError());
1077 return TRUE;
1081 /******************************************************************************
1082 * fpAddMonitor [exported through PRINTPROVIDOR]
1084 * Install a Printmonitor
1086 * PARAMS
1087 * pName [I] Servername or NULL (local Computer)
1088 * Level [I] Structure-Level (Must be 2)
1089 * pMonitors [I] PTR to MONITOR_INFO_2
1091 * RETURNS
1092 * Success: TRUE
1093 * Failure: FALSE
1095 * NOTES
1096 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1099 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1101 monitor_t * pm = NULL;
1102 LPMONITOR_INFO_2W mi2w;
1103 HKEY hroot = NULL;
1104 HKEY hentry = NULL;
1105 DWORD disposition;
1106 BOOL res = FALSE;
1108 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1109 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1110 debugstr_w(mi2w ? mi2w->pName : NULL),
1111 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1112 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1114 if (copy_servername_from_name(pName, NULL)) {
1115 FIXME("server %s not supported\n", debugstr_w(pName));
1116 SetLastError(ERROR_ACCESS_DENIED);
1117 return FALSE;
1120 if (!mi2w->pName || (! mi2w->pName[0])) {
1121 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1122 SetLastError(ERROR_INVALID_PARAMETER);
1123 return FALSE;
1125 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1126 WARN("Environment %s requested (we support only %s)\n",
1127 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1128 SetLastError(ERROR_INVALID_ENVIRONMENT);
1129 return FALSE;
1132 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1133 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1134 SetLastError(ERROR_INVALID_PARAMETER);
1135 return FALSE;
1138 /* Load and initialize the monitor. SetLastError() is called on failure */
1139 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1140 return FALSE;
1142 monitor_unload(pm);
1144 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1145 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1146 return FALSE;
1149 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1150 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1151 &disposition) == ERROR_SUCCESS) {
1153 /* Some installers set options for the port before calling AddMonitor.
1154 We query the "Driver" entry to verify that the monitor is installed,
1155 before we return an error.
1156 When a user installs two print monitors at the same time with the
1157 same name, a race condition is possible but silently ignored. */
1159 DWORD namesize = 0;
1161 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1162 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1163 &namesize) == ERROR_SUCCESS)) {
1164 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1165 /* 9x use ERROR_ALREADY_EXISTS */
1166 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1168 else
1170 INT len;
1171 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1172 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1173 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1175 RegCloseKey(hentry);
1178 RegCloseKey(hroot);
1179 return (res);
1182 /******************************************************************************
1183 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1185 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1187 * PARAMS
1188 * pName [I] Servername or NULL (local Computer)
1189 * level [I] Level for the supplied DRIVER_INFO_*W struct
1190 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1191 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1193 * RESULTS
1194 * Success: TRUE
1195 * Failure: FALSE
1198 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1200 LONG lres;
1202 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1203 lres = copy_servername_from_name(pName, NULL);
1204 if (lres) {
1205 FIXME("server %s not supported\n", debugstr_w(pName));
1206 SetLastError(ERROR_ACCESS_DENIED);
1207 return FALSE;
1210 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1211 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1214 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1216 /******************************************************************
1217 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1219 * Delete a specific Printmonitor from a Printing-Environment
1221 * PARAMS
1222 * pName [I] Servername or NULL (local Computer)
1223 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1224 * pMonitorName [I] Name of the Monitor, that should be deleted
1226 * RETURNS
1227 * Success: TRUE
1228 * Failure: FALSE
1230 * NOTES
1231 * pEnvironment is ignored in Windows for the local Computer.
1235 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1237 HKEY hroot = NULL;
1238 LONG lres;
1240 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1241 debugstr_w(pMonitorName));
1243 lres = copy_servername_from_name(pName, NULL);
1244 if (lres) {
1245 FIXME("server %s not supported\n", debugstr_w(pName));
1246 SetLastError(ERROR_INVALID_NAME);
1247 return FALSE;
1250 /* pEnvironment is ignored in Windows for the local Computer */
1251 if (!pMonitorName || !pMonitorName[0]) {
1252 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1253 SetLastError(ERROR_INVALID_PARAMETER);
1254 return FALSE;
1257 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1258 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1259 return FALSE;
1262 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1263 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1264 RegCloseKey(hroot);
1265 return TRUE;
1268 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1269 RegCloseKey(hroot);
1271 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1272 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1273 return FALSE;
1276 /*****************************************************************************
1277 * fpEnumMonitors [exported through PRINTPROVIDOR]
1279 * Enumerate available Port-Monitors
1281 * PARAMS
1282 * pName [I] Servername or NULL (local Computer)
1283 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1284 * pMonitors [O] PTR to Buffer that receives the Result
1285 * cbBuf [I] Size of Buffer at pMonitors
1286 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1287 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1289 * RETURNS
1290 * Success: TRUE
1291 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1293 * NOTES
1294 * Windows reads the Registry once and cache the Results.
1297 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1298 LPDWORD pcbNeeded, LPDWORD pcReturned)
1300 DWORD numentries = 0;
1301 DWORD needed = 0;
1302 LONG lres;
1303 BOOL res = FALSE;
1305 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1306 cbBuf, pcbNeeded, pcReturned);
1308 lres = copy_servername_from_name(pName, NULL);
1309 if (lres) {
1310 FIXME("server %s not supported\n", debugstr_w(pName));
1311 SetLastError(ERROR_INVALID_NAME);
1312 goto em_cleanup;
1315 if (!Level || (Level > 2)) {
1316 WARN("level (%d) is ignored in win9x\n", Level);
1317 SetLastError(ERROR_INVALID_LEVEL);
1318 return FALSE;
1321 /* Scan all Monitor-Keys */
1322 numentries = 0;
1323 needed = get_local_monitors(Level, NULL, 0, &numentries);
1325 /* we calculated the needed buffersize. now do more error-checks */
1326 if (cbBuf < needed) {
1327 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1328 goto em_cleanup;
1331 /* fill the Buffer with the Monitor-Keys */
1332 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1333 res = TRUE;
1335 em_cleanup:
1336 if (pcbNeeded) *pcbNeeded = needed;
1337 if (pcReturned) *pcReturned = numentries;
1339 TRACE("returning %d with %d (%d byte for %d entries)\n",
1340 res, GetLastError(), needed, numentries);
1342 return (res);
1345 /******************************************************************************
1346 * fpEnumPorts [exported through PRINTPROVIDOR]
1348 * Enumerate available Ports
1350 * PARAMS
1351 * pName [I] Servername or NULL (local Computer)
1352 * Level [I] Structure-Level (1 or 2)
1353 * pPorts [O] PTR to Buffer that receives the Result
1354 * cbBuf [I] Size of Buffer at pPorts
1355 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1356 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1358 * RETURNS
1359 * Success: TRUE
1360 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1363 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1364 LPDWORD pcbNeeded, LPDWORD pcReturned)
1366 DWORD needed = 0;
1367 DWORD numentries = 0;
1368 LONG lres;
1369 BOOL res = FALSE;
1371 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1372 cbBuf, pcbNeeded, pcReturned);
1374 lres = copy_servername_from_name(pName, NULL);
1375 if (lres) {
1376 FIXME("server %s not supported\n", debugstr_w(pName));
1377 SetLastError(ERROR_INVALID_NAME);
1378 goto emP_cleanup;
1381 if (!Level || (Level > 2)) {
1382 SetLastError(ERROR_INVALID_LEVEL);
1383 goto emP_cleanup;
1386 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1387 SetLastError(RPC_X_NULL_REF_POINTER);
1388 goto emP_cleanup;
1391 EnterCriticalSection(&monitor_handles_cs);
1392 monitor_loadall();
1394 /* Scan all local Ports */
1395 numentries = 0;
1396 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1398 /* we calculated the needed buffersize. now do the error-checks */
1399 if (cbBuf < needed) {
1400 monitor_unloadall();
1401 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1402 goto emP_cleanup_cs;
1404 else if (!pPorts || !pcReturned) {
1405 monitor_unloadall();
1406 SetLastError(RPC_X_NULL_REF_POINTER);
1407 goto emP_cleanup_cs;
1410 /* Fill the Buffer */
1411 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1412 res = TRUE;
1413 monitor_unloadall();
1415 emP_cleanup_cs:
1416 LeaveCriticalSection(&monitor_handles_cs);
1418 emP_cleanup:
1419 if (pcbNeeded) *pcbNeeded = needed;
1420 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1422 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1423 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1425 return (res);
1428 /*****************************************************
1429 * setup_provider [internal]
1431 void setup_provider(void)
1433 static const PRINTPROVIDOR backend = {
1434 NULL, /* fpOpenPrinter */
1435 NULL, /* fpSetJob */
1436 NULL, /* fpGetJob */
1437 NULL, /* fpEnumJobs */
1438 NULL, /* fpAddPrinter */
1439 NULL, /* fpDeletePrinter */
1440 NULL, /* fpSetPrinter */
1441 NULL, /* fpGetPrinter */
1442 NULL, /* fpEnumPrinters */
1443 NULL, /* fpAddPrinterDriver */
1444 NULL, /* fpEnumPrinterDrivers */
1445 NULL, /* fpGetPrinterDriver */
1446 fpGetPrinterDriverDirectory,
1447 NULL, /* fpDeletePrinterDriver */
1448 NULL, /* fpAddPrintProcessor */
1449 NULL, /* fpEnumPrintProcessors */
1450 NULL, /* fpGetPrintProcessorDirectory */
1451 NULL, /* fpDeletePrintProcessor */
1452 NULL, /* fpEnumPrintProcessorDatatypes */
1453 NULL, /* fpStartDocPrinter */
1454 NULL, /* fpStartPagePrinter */
1455 NULL, /* fpWritePrinter */
1456 NULL, /* fpEndPagePrinter */
1457 NULL, /* fpAbortPrinter */
1458 NULL, /* fpReadPrinter */
1459 NULL, /* fpEndDocPrinter */
1460 NULL, /* fpAddJob */
1461 NULL, /* fpScheduleJob */
1462 NULL, /* fpGetPrinterData */
1463 NULL, /* fpSetPrinterData */
1464 NULL, /* fpWaitForPrinterChange */
1465 NULL, /* fpClosePrinter */
1466 NULL, /* fpAddForm */
1467 NULL, /* fpDeleteForm */
1468 NULL, /* fpGetForm */
1469 NULL, /* fpSetForm */
1470 NULL, /* fpEnumForms */
1471 fpEnumMonitors,
1472 fpEnumPorts,
1473 NULL, /* fpAddPort */
1474 NULL, /* fpConfigurePort */
1475 NULL, /* fpDeletePort */
1476 NULL, /* fpCreatePrinterIC */
1477 NULL, /* fpPlayGdiScriptOnPrinterIC */
1478 NULL, /* fpDeletePrinterIC */
1479 NULL, /* fpAddPrinterConnection */
1480 NULL, /* fpDeletePrinterConnection */
1481 NULL, /* fpPrinterMessageBox */
1482 fpAddMonitor,
1483 fpDeleteMonitor,
1484 NULL, /* fpResetPrinter */
1485 NULL, /* fpGetPrinterDriverEx */
1486 NULL, /* fpFindFirstPrinterChangeNotification */
1487 NULL, /* fpFindClosePrinterChangeNotification */
1488 NULL, /* fpAddPortEx */
1489 NULL, /* fpShutDown */
1490 NULL, /* fpRefreshPrinterChangeNotification */
1491 NULL, /* fpOpenPrinterEx */
1492 NULL, /* fpAddPrinterEx */
1493 NULL, /* fpSetPort */
1494 NULL, /* fpEnumPrinterData */
1495 NULL, /* fpDeletePrinterData */
1496 NULL, /* fpClusterSplOpen */
1497 NULL, /* fpClusterSplClose */
1498 NULL, /* fpClusterSplIsAlive */
1499 NULL, /* fpSetPrinterDataEx */
1500 NULL, /* fpGetPrinterDataEx */
1501 NULL, /* fpEnumPrinterDataEx */
1502 NULL, /* fpEnumPrinterKey */
1503 NULL, /* fpDeletePrinterDataEx */
1504 NULL, /* fpDeletePrinterKey */
1505 NULL, /* fpSeekPrinter */
1506 NULL, /* fpDeletePrinterDriverEx */
1507 NULL, /* fpAddPerMachineConnection */
1508 NULL, /* fpDeletePerMachineConnection */
1509 NULL, /* fpEnumPerMachineConnections */
1510 NULL, /* fpXcvData */
1511 fpAddPrinterDriverEx,
1512 NULL, /* fpSplReadPrinter */
1513 NULL, /* fpDriverUnloadComplete */
1514 NULL, /* fpGetSpoolFileInfo */
1515 NULL, /* fpCommitSpoolData */
1516 NULL, /* fpCloseSpoolFileHandle */
1517 NULL, /* fpFlushPrinter */
1518 NULL, /* fpSendRecvBidiData */
1519 NULL /* fpAddDriverCatalog */
1521 pprovider = &backend;
1525 /*****************************************************
1526 * InitializePrintProvidor (localspl.@)
1528 * Initialize the Printprovider
1530 * PARAMS
1531 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1532 * cbPrintProvidor [I] Size of Buffer in Bytes
1533 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1535 * RETURNS
1536 * Success: TRUE and pPrintProvidor filled
1537 * Failure: FALSE
1539 * NOTES
1540 * The RegistryPath should be:
1541 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1542 * but this Parameter is ignored in "localspl.dll".
1546 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1547 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1550 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1551 memcpy(pPrintProvidor, pprovider,
1552 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1554 return TRUE;