[PATCH] localspl: Move provider functions to a seperate file

Detlef Riekenberg wine.dev at web.de
Sun Feb 8 09:38:30 CST 2009


---
 dlls/localspl/Makefile.in        |    3 +-
 dlls/localspl/localspl_main.c    | 1302 +-------------------------------------
 dlls/localspl/localspl_private.h |    1 +
 dlls/localspl/provider.c         | 1327 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 1333 insertions(+), 1300 deletions(-)
 create mode 100644 dlls/localspl/provider.c

diff --git a/dlls/localspl/Makefile.in b/dlls/localspl/Makefile.in
index c3691e8..4850363 100644
--- a/dlls/localspl/Makefile.in
+++ b/dlls/localspl/Makefile.in
@@ -7,7 +7,8 @@ IMPORTS   = spoolss user32 advapi32 kernel32
 
 C_SRCS = \
 	localmon.c \
-	localspl_main.c
+	localspl_main.c \
+	provider.c
 
 RC_SRCS = localspl.rc
 
diff --git a/dlls/localspl/localspl_main.c b/dlls/localspl/localspl_main.c
index 18b51ac..953f017 100644
--- a/dlls/localspl/localspl_main.c
+++ b/dlls/localspl/localspl_main.c
@@ -1,7 +1,7 @@
 /*
- * Implementation of the Local Printmonitor
+ * Implementation of the Local Printprovider/ Printmonitor/ Prontprocessor
  *
- * Copyright 2006-2008 Detlef Riekenberg
+ * Copyright 2006-2009 Detlef Riekenberg
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,1280 +25,15 @@
 
 #include "windef.h"
 #include "winbase.h"
-#include "wingdi.h"
-#include "winreg.h"
-#include "winspool.h"
-#include "winuser.h"
-#include "ddk/winddiui.h"
-#include "ddk/winsplp.h"
 
-#include "wine/list.h"
 #include "wine/debug.h"
-#include "wine/unicode.h"
 #include "localspl_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
 
-/* ############################### */
-
-static CRITICAL_SECTION monitor_handles_cs;
-static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
-{
-    0, 0, &monitor_handles_cs,
-    { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
-};
-static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
-
-/* ############################### */
-
-typedef struct {
-    WCHAR   src[MAX_PATH+MAX_PATH];
-    WCHAR   dst[MAX_PATH+MAX_PATH];
-    DWORD   srclen;
-    DWORD   dstlen;
-    DWORD   copyflags;
-    BOOL    lazy;
-} apd_data_t;
-
-typedef struct {
-    struct list     entry;
-    LPWSTR          name;
-    LPWSTR          dllname;
-    PMONITORUI      monitorUI;
-    LPMONITOR       monitor;
-    HMODULE         hdll;
-    DWORD           refcount;
-    DWORD           dwMonitorSize;
-} monitor_t;
-
-typedef struct {
-    LPCWSTR  envname;
-    LPCWSTR  subdir;
-    DWORD    driverversion;
-    LPCWSTR  versionregpath;
-    LPCWSTR  versionsubdir;
-} printenv_t;
-
-
-/* ############################### */
-
-static struct list monitor_handles = LIST_INIT( monitor_handles );
-static monitor_t * pm_localport;
 
 HINSTANCE LOCALSPL_hInstance = NULL;
 
-static const PRINTPROVIDOR * pp = NULL;
-
-static const WCHAR backslashW[] = {'\\',0};
-static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
-static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
-static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
-static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
-static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
-static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
-static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
-static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
-                                  'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-                                  'c','o','n','t','r','o','l','\\',
-                                  'P','r','i','n','t','\\',
-                                  'E','n','v','i','r','o','n','m','e','n','t','s','\\',
-                                  '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
-static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
-static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
-static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
-static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
-static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
-static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
-static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
-                                'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-                                'C','o','n','t','r','o','l','\\',
-                                'P','r','i','n','t','\\',
-                                'M','o','n','i','t','o','r','s','\\',0};
-static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
-static const WCHAR nameW[] = {'N','a','m','e',0};
-static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
-static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
-static const WCHAR portW[] = {'P','o','r','t',0};
-static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
-static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
-static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
-
-static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
-static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
-static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
-static const WCHAR version0_subdirW[] = {'\\','0',0};
-
-static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
-static const WCHAR x64_subdirW[] = {'x','6','4',0};
-static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
-static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
-static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
-static const WCHAR version3_subdirW[] = {'\\','3',0};
-
-
-static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
-                                     version3_regpathW, version3_subdirW};
-
-static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
-                                     version3_regpathW, version3_subdirW};
-
-static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
-                                     version0_regpathW, version0_subdirW};
-
-static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
-
-
-static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
-                                     sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
-                                     sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
-                                  0, sizeof(DRIVER_INFO_8W)};
-
-
-/******************************************************************
- * strdupW [internal]
- *
- * create a copy of a unicode-string
- *
- */
-
-static LPWSTR strdupW(LPCWSTR p)
-{
-    LPWSTR ret;
-    DWORD len;
-
-    if(!p) return NULL;
-    len = (lstrlenW(p) + 1) * sizeof(WCHAR);
-    ret = heap_alloc(len);
-    memcpy(ret, p, len);
-    return ret;
-}
-
-/******************************************************************
- *  apd_copyfile [internal]
- *
- * Copy a file from the driverdirectory to the versioned directory
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE
- *
- */
-static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
-{
-    LPWSTR  ptr;
-    LPWSTR  srcname;
-    DWORD   res;
-
-    apd->src[apd->srclen] = '\0';
-    apd->dst[apd->dstlen] = '\0';
-
-    if (!filename || !filename[0]) {
-        /* nothing to copy */
-        return TRUE;
-    }
-
-    ptr = strrchrW(filename, '\\');
-    if (ptr) {
-        ptr++;
-    }
-    else
-    {
-        ptr = filename;
-    }
-
-    if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
-        /* we have an absolute Path */
-        srcname = filename;
-    }
-    else
-    {
-        srcname = apd->src;
-        lstrcatW(srcname, ptr);
-    }
-    lstrcatW(apd->dst, ptr);
-
-    TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
-
-    /* FIXME: handle APD_COPY_NEW_FILES */
-    res = CopyFileW(srcname, apd->dst, FALSE);
-    TRACE("got %u with %u\n", res, GetLastError());
-
-    return (apd->lazy) ? TRUE : res;
-}
-
-/******************************************************************
- * copy_servername_from_name  (internal)
- *
- * for an external server, the serverpart from the name is copied.
- *
- * RETURNS
- *  the length (in WCHAR) of the serverpart (0 for the local computer)
- *  (-length), when the name is to long
- *
- */
-static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
-{
-    LPCWSTR server;
-    LPWSTR  ptr;
-    WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
-    DWORD   len;
-    DWORD   serverlen;
-
-    if (target) *target = '\0';
-
-    if (name == NULL) return 0;
-    if ((name[0] != '\\') || (name[1] != '\\')) return 0;
-
-    server = &name[2];
-    /* skip over both backslash, find separator '\' */
-    ptr = strchrW(server, '\\');
-    serverlen = (ptr) ? ptr - server : lstrlenW(server);
-
-    /* servername is empty or to long */
-    if (serverlen == 0) return 0;
-
-    TRACE("found %s\n", debugstr_wn(server, serverlen));
-
-    if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
-
-    len = sizeof(buffer) / sizeof(buffer[0]);
-    if (GetComputerNameW(buffer, &len)) {
-        if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
-            /* The requested Servername is our computername */
-            if (target) {
-                memcpy(target, server, serverlen * sizeof(WCHAR));
-                target[serverlen] = '\0';
-            }
-            return serverlen;
-        }
-    }
-    return 0;
-}
-
-/******************************************************************
- * monitor_unload [internal]
- *
- * release a printmonitor and unload it from memory, when needed
- *
- */
-static void monitor_unload(monitor_t * pm)
-{
-    if (pm == NULL) return;
-    TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
-
-    EnterCriticalSection(&monitor_handles_cs);
-
-    if (pm->refcount) pm->refcount--;
-
-    if (pm->refcount == 0) {
-        list_remove(&pm->entry);
-        FreeLibrary(pm->hdll);
-        heap_free(pm->name);
-        heap_free(pm->dllname);
-        heap_free(pm);
-    }
-    LeaveCriticalSection(&monitor_handles_cs);
-}
-
-/******************************************************************
- * monitor_load [internal]
- *
- * load a printmonitor, get the dllname from the registry, when needed
- * initialize the monitor and dump found function-pointers
- *
- * On failure, SetLastError() is called and NULL is returned
- */
-
-static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
-{
-    LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
-    PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
-    LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
-    DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
-    DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
-
-    monitor_t * pm = NULL;
-    monitor_t * cursor;
-    LPWSTR  regroot = NULL;
-    LPWSTR  driver = dllname;
-
-    TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
-    /* Is the Monitor already loaded? */
-    EnterCriticalSection(&monitor_handles_cs);
-
-    if (name) {
-        LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
-        {
-            if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
-                pm = cursor;
-                break;
-            }
-        }
-    }
-
-    if (pm == NULL) {
-        pm = heap_alloc_zero(sizeof(monitor_t));
-        if (pm == NULL) goto cleanup;
-        list_add_tail(&monitor_handles, &pm->entry);
-    }
-    pm->refcount++;
-
-    if (pm->name == NULL) {
-        /* Load the monitor */
-        LPMONITOREX pmonitorEx;
-        DWORD   len;
-
-        if (name) {
-            len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
-            regroot = heap_alloc(len * sizeof(WCHAR));
-        }
-
-        if (regroot) {
-            lstrcpyW(regroot, monitorsW);
-            lstrcatW(regroot, name);
-            /* Get the Driver from the Registry */
-            if (driver == NULL) {
-                HKEY    hroot;
-                DWORD   namesize;
-                if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
-                    if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
-                                        &namesize) == ERROR_SUCCESS) {
-                        driver = heap_alloc(namesize);
-                        RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
-                    }
-                    RegCloseKey(hroot);
-                }
-            }
-        }
-
-        pm->name = strdupW(name);
-        pm->dllname = strdupW(driver);
-
-        if ((name && (!regroot || !pm->name)) || !pm->dllname) {
-            monitor_unload(pm);
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            pm = NULL;
-            goto cleanup;
-        }
-
-        pm->hdll = LoadLibraryW(driver);
-        TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
-
-        if (pm->hdll == NULL) {
-            monitor_unload(pm);
-            SetLastError(ERROR_MOD_NOT_FOUND);
-            pm = NULL;
-            goto cleanup;
-        }
-
-        pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
-        pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
-        pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
-        pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
-        pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
-
-
-        TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
-        TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
-        TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
-        TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
-        TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
-
-        if (pInitializePrintMonitorUI  != NULL) {
-            pm->monitorUI = pInitializePrintMonitorUI();
-            TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
-            if (pm->monitorUI) {
-                TRACE("0x%08x: dwMonitorSize (%d)\n",
-                        pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
-
-            }
-        }
-
-        if (pInitializePrintMonitor && regroot) {
-            pmonitorEx = pInitializePrintMonitor(regroot);
-            TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
-                    pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
-
-            if (pmonitorEx) {
-                pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
-                pm->monitor = &(pmonitorEx->Monitor);
-            }
-        }
-
-        if (pm->monitor) {
-            TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
-
-        }
-
-        if (!pm->monitor && regroot) {
-            if (pInitializePrintMonitor2 != NULL) {
-                FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
-            }
-            if (pInitializeMonitorEx != NULL) {
-                FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
-            }
-            if (pInitializeMonitor != NULL) {
-                FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
-            }
-        }
-        if (!pm->monitor && !pm->monitorUI) {
-            monitor_unload(pm);
-            SetLastError(ERROR_PROC_NOT_FOUND);
-            pm = NULL;
-        }
-    }
-cleanup:
-    if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
-        pm->refcount++;
-        pm_localport = pm;
-    }
-    LeaveCriticalSection(&monitor_handles_cs);
-    if (driver != dllname) heap_free(driver);
-    heap_free(regroot);
-    TRACE("=> %p\n", pm);
-    return pm;
-}
-
-/******************************************************************
- * Return the number of bytes for an multi_sz string.
- * The result includes all \0s
- * (specifically the extra \0, that is needed as multi_sz terminator).
- */
-static int multi_sz_lenW(const WCHAR *str)
-{
-    const WCHAR *ptr = str;
-    if (!str) return 0;
-    do
-    {
-        ptr += lstrlenW(ptr) + 1;
-    } while (*ptr);
-
-    return (ptr - str + 1) * sizeof(WCHAR);
-}
-
-/******************************************************************
- * validate_envW [internal]
- *
- * validate the user-supplied printing-environment
- *
- * PARAMS
- *  env  [I] PTR to Environment-String or NULL
- *
- * RETURNS
- *  Success:  PTR to printenv_t
- *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
- *
- * NOTES
- *  An empty string is handled the same way as NULL.
- *
- */
-
-static const  printenv_t * validate_envW(LPCWSTR env)
-{
-    const printenv_t *result = NULL;
-    unsigned int i;
-
-    TRACE("(%s)\n", debugstr_w(env));
-    if (env && env[0])
-    {
-        for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
-        {
-            if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
-            {
-                result = all_printenv[i];
-                break;
-            }
-        }
-        if (result == NULL) {
-            FIXME("unsupported Environment: %s\n", debugstr_w(env));
-            SetLastError(ERROR_INVALID_ENVIRONMENT);
-        }
-        /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
-    }
-    else
-    {
-        result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
-    }
-
-    TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
-    return result;
-}
-
-/*****************************************************************************
- * enumerate the local monitors (INTERNAL)
- *
- * returns the needed size (in bytes) for pMonitors
- * and  *lpreturned is set to number of entries returned in pMonitors
- *
- * Language-Monitors are also installed in the same Registry-Location but
- * they are filtered in Windows (not returned by EnumMonitors).
- * We do no filtering to simplify our Code.
- *
- */
-static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
-{
-    HKEY    hroot = NULL;
-    HKEY    hentry = NULL;
-    LPWSTR  ptr;
-    LPMONITOR_INFO_2W mi;
-    WCHAR   buffer[MAX_PATH];
-    WCHAR   dllname[MAX_PATH];
-    DWORD   dllsize;
-    DWORD   len;
-    DWORD   index = 0;
-    DWORD   needed = 0;
-    DWORD   numentries;
-    DWORD   entrysize;
-
-    entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
-
-    numentries = *lpreturned;       /* this is 0, when we scan the registry */
-    len = entrysize * numentries;
-    ptr = (LPWSTR) &pMonitors[len];
-
-    numentries = 0;
-    len = sizeof(buffer)/sizeof(buffer[0]);
-    buffer[0] = '\0';
-
-    /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
-    if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
-        /* Scan all Monitor-Registry-Keys */
-        while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
-            TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
-            dllsize = sizeof(dllname);
-            dllname[0] = '\0';
-
-            /* The Monitor must have a Driver-DLL */
-            if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
-                if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
-                    /* We found a valid DLL for this Monitor. */
-                    TRACE("using Driver: %s\n", debugstr_w(dllname));
-                }
-                RegCloseKey(hentry);
-            }
-
-            /* Windows returns only Port-Monitors here, but to simplify our code,
-               we do no filtering for Language-Monitors */
-            if (dllname[0]) {
-                numentries++;
-                needed += entrysize;
-                needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
-                if (level > 1) {
-                    /* we install and return only monitors for "Windows NT x86" */
-                    needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
-                    needed += dllsize;
-                }
-
-                /* required size is calculated. Now fill the user-buffer */
-                if (pMonitors && (cbBuf >= needed)){
-                    mi = (LPMONITOR_INFO_2W) pMonitors;
-                    pMonitors += entrysize;
-
-                    TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
-                    mi->pName = ptr;
-                    lstrcpyW(ptr, buffer);      /* Name of the Monitor */
-                    ptr += (len+1);               /* len is lstrlenW(monitorname) */
-                    if (level > 1) {
-                        mi->pEnvironment = ptr;
-                        lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
-                        ptr += (lstrlenW(x86_envnameW)+1);
-
-                        mi->pDLLName = ptr;
-                        lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
-                        ptr += (dllsize / sizeof(WCHAR));
-                    }
-                }
-            }
-            index++;
-            len = sizeof(buffer)/sizeof(buffer[0]);
-            buffer[0] = '\0';
-        }
-        RegCloseKey(hroot);
-    }
-    *lpreturned = numentries;
-    TRACE("need %d byte for %d entries\n", needed, numentries);
-    return needed;
-}
-
-/*****************************************************************************
- * open_driver_reg [internal]
- *
- * opens the registry for the printer drivers depending on the given input
- * variable pEnvironment
- *
- * RETURNS:
- *    Success: the opened hkey
- *    Failure: NULL
- */
-static HKEY open_driver_reg(LPCWSTR pEnvironment)
-{
-    HKEY  retval = NULL;
-    LPWSTR buffer;
-    const printenv_t * env;
-
-    TRACE("(%s)\n", debugstr_w(pEnvironment));
-
-    env = validate_envW(pEnvironment);
-    if (!env) return NULL;
-
-    buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
-                (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
-
-    if (buffer) {
-        wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
-        RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
-        HeapFree(GetProcessHeap(), 0, buffer);
-    }
-    return retval;
-}
-
-/*****************************************************************************
- * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
- *
- * Return the PATH for the Printer-Drivers
- *
- * PARAMS
- *   pName            [I] Servername (NT only) or NULL (local Computer)
- *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
- *   Level            [I] Structure-Level (must be 1)
- *   pDriverDirectory [O] PTR to Buffer that receives the Result
- *   cbBuf            [I] Size of Buffer at pDriverDirectory
- *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
- *                        required for pDriverDirectory
- *
- * RETURNS
- *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
- *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
- *            if cbBuf is too small
- *
- *   Native Values returned in pDriverDirectory on Success:
- *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
- *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
- *|  win9x(Windows 4.0):  "%winsysdir%"
- *
- *   "%winsysdir%" is the Value from GetSystemDirectoryW()
- *
- */
-static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
-            DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
-{
-    DWORD needed;
-    const printenv_t * env;
-
-    TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
-          debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
-
-    if (pName != NULL && pName[0]) {
-        FIXME("server %s not supported\n", debugstr_w(pName));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    env = validate_envW(pEnvironment);
-    if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
-
-
-    /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
-    needed = GetSystemDirectoryW(NULL, 0);
-    /* add the Size for the Subdirectories */
-    needed += lstrlenW(spooldriversW);
-    needed += lstrlenW(env->subdir);
-    needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
-
-    *pcbNeeded = needed;
-
-    if (needed > cbBuf) {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-        return FALSE;
-    }
-
-    if (pDriverDirectory == NULL) {
-        /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-        return FALSE;
-    }
-
-    GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
-    /* add the Subdirectories */
-    lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
-    lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
-
-    TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
-    return TRUE;
-}
-
-/******************************************************************
- * driver_load [internal]
- *
- * load a driver user interface dll
- *
- * On failure, NULL is returned
- *
- */
-
-static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
-{
-    WCHAR fullname[MAX_PATH];
-    HMODULE hui;
-    DWORD len;
-
-    TRACE("(%p, %s)\n", env, debugstr_w(dllname));
-
-    /* build the driverdir */
-    len = sizeof(fullname) -
-          (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
-
-    if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
-                                     (LPBYTE) fullname, len, &len)) {
-        /* Should never Fail */
-        SetLastError(ERROR_BUFFER_OVERFLOW);
-        return NULL;
-    }
-
-    lstrcatW(fullname, env->versionsubdir);
-    lstrcatW(fullname, backslashW);
-    lstrcatW(fullname, dllname);
-
-    hui = LoadLibraryW(fullname);
-    TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
-
-    return hui;
-}
-
-/******************************************************************************
- *  myAddPrinterDriverEx [internal]
- *
- * Install a Printer Driver with the Option to upgrade / downgrade the Files
- * and a special mode with lazy error checking.
- *
- */
-static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
-{
-    static const WCHAR emptyW[1];
-    const printenv_t *env;
-    apd_data_t apd;
-    DRIVER_INFO_8W di;
-    BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
-    HMODULE hui;
-    LPWSTR  ptr;
-    HKEY    hroot;
-    HKEY    hdrv;
-    DWORD   disposition;
-    DWORD   len;
-    LONG    lres;
-    BOOL    res;
-
-    /* we need to set all entries in the Registry, independent from the Level of
-       DRIVER_INFO, that the caller supplied */
-
-    ZeroMemory(&di, sizeof(di));
-    if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
-        memcpy(&di, pDriverInfo, di_sizeof[level]);
-    }
-
-    /* dump the most used infos */
-    TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
-    TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
-    TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
-    TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
-    TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
-    TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
-    TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
-    /* dump only the first of the additional Files */
-    TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
-
-
-    /* check environment */
-    env = validate_envW(di.pEnvironment);
-    if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
-
-    /* fill the copy-data / get the driverdir */
-    len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
-    if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
-                                    (LPBYTE) apd.src, len, &len)) {
-        /* Should never Fail */
-        return FALSE;
-    }
-    memcpy(apd.dst, apd.src, len);
-    lstrcatW(apd.src, backslashW);
-    apd.srclen = lstrlenW(apd.src);
-    lstrcatW(apd.dst, env->versionsubdir);
-    lstrcatW(apd.dst, backslashW);
-    apd.dstlen = lstrlenW(apd.dst);
-    apd.copyflags = dwFileCopyFlags;
-    apd.lazy = lazy;
-    CreateDirectoryW(apd.src, NULL);
-    CreateDirectoryW(apd.dst, NULL);
-
-    hroot = open_driver_reg(env->envname);
-    if (!hroot) {
-        ERR("Can't create Drivers key\n");
-        return FALSE;
-    }
-
-    /* Fill the Registry for the Driver */
-    if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
-                                KEY_WRITE | KEY_QUERY_VALUE, NULL,
-                                &hdrv, &disposition)) != ERROR_SUCCESS) {
-
-        ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
-        RegCloseKey(hroot);
-        SetLastError(lres);
-        return FALSE;
-    }
-    RegCloseKey(hroot);
-
-    if (disposition == REG_OPENED_EXISTING_KEY) {
-        TRACE("driver %s already installed\n", debugstr_w(di.pName));
-        RegCloseKey(hdrv);
-        SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
-        return FALSE;
-    }
-
-    /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
-    RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
-                   sizeof(DWORD));
-
-    RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
-                   (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
-    apd_copyfile(di.pDriverPath, &apd);
-
-    RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
-                   (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
-    apd_copyfile(di.pDataFile, &apd);
-
-    RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
-                   (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
-    apd_copyfile(di.pConfigFile, &apd);
-
-    /* settings for level 3 */
-    if (di.pHelpFile)
-        RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
-                       (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
-    else
-        RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
-    apd_copyfile(di.pHelpFile, &apd);
-
-
-    ptr = di.pDependentFiles;
-    if (ptr)
-        RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
-                       multi_sz_lenW(di.pDependentFiles));
-    else
-        RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
-    while ((ptr != NULL) && (ptr[0])) {
-        if (apd_copyfile(ptr, &apd)) {
-            ptr += lstrlenW(ptr) + 1;
-        }
-        else
-        {
-            WARN("Failed to copy %s\n", debugstr_w(ptr));
-            ptr = NULL;
-        }
-    }
-    /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
-    if (di.pMonitorName)
-        RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
-                       (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
-    else
-        RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
-
-    if (di.pDefaultDataType)
-        RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
-                       (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
-    else
-        RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
-
-    /* settings for level 4 */
-    if (di.pszzPreviousNames)
-        RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
-                       multi_sz_lenW(di.pszzPreviousNames));
-    else
-        RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
-
-    if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
-
-    RegCloseKey(hdrv);
-    hui = driver_load(env, di.pConfigFile);
-    pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
-    if (hui && pDrvDriverEvent) {
-
-        /* Support for DrvDriverEvent is optional */
-        TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
-        /* MSDN: level for DRIVER_INFO is 1 to 3 */
-        res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
-        TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
-    }
-    FreeLibrary(hui);
-
-    TRACE("=> TRUE with %u\n", GetLastError());
-    return TRUE;
-
-}
-
-/******************************************************************************
- * fpAddMonitor [exported through PRINTPROVIDOR]
- *
- * Install a Printmonitor
- *
- * PARAMS
- *  pName       [I] Servername or NULL (local Computer)
- *  Level       [I] Structure-Level (Must be 2)
- *  pMonitors   [I] PTR to MONITOR_INFO_2
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE
- *
- * NOTES
- *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
- *
- */
-static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
-{
-    monitor_t * pm = NULL;
-    LPMONITOR_INFO_2W mi2w;
-    HKEY    hroot = NULL;
-    HKEY    hentry = NULL;
-    DWORD   disposition;
-    BOOL    res = FALSE;
-
-    mi2w = (LPMONITOR_INFO_2W) pMonitors;
-    TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
-            debugstr_w(mi2w ? mi2w->pName : NULL),
-            debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
-            debugstr_w(mi2w ? mi2w->pDLLName : NULL));
-
-    if (copy_servername_from_name(pName, NULL)) {
-        FIXME("server %s not supported\n", debugstr_w(pName));
-        SetLastError(ERROR_ACCESS_DENIED);
-        return FALSE;
-    }
-
-    if (!mi2w->pName || (! mi2w->pName[0])) {
-        WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-    if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
-        WARN("Environment %s requested (we support only %s)\n",
-                debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
-        SetLastError(ERROR_INVALID_ENVIRONMENT);
-        return FALSE;
-    }
-
-    if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
-        WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    /* Load and initialize the monitor. SetLastError() is called on failure */
-    if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
-        return FALSE;
-    }
-    monitor_unload(pm);
-
-    if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
-        ERR("unable to create key %s\n", debugstr_w(monitorsW));
-        return FALSE;
-    }
-
-    if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
-                        KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
-                        &disposition) == ERROR_SUCCESS) {
-
-        /* Some installers set options for the port before calling AddMonitor.
-           We query the "Driver" entry to verify that the monitor is installed,
-           before we return an error.
-           When a user installs two print monitors at the same time with the
-           same name, a race condition is possible but silently ignored. */
-
-        DWORD   namesize = 0;
-
-        if ((disposition == REG_OPENED_EXISTING_KEY) &&
-            (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
-                              &namesize) == ERROR_SUCCESS)) {
-            TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
-            /* 9x use ERROR_ALREADY_EXISTS */
-            SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
-        }
-        else
-        {
-            INT len;
-            len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
-            res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
-                    (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
-        }
-        RegCloseKey(hentry);
-    }
-
-    RegCloseKey(hroot);
-    return (res);
-}
-
-/******************************************************************************
- * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
- *
- * Install a Printer Driver with the Option to upgrade / downgrade the Files
- *
- * PARAMS
- *  pName           [I] Servername or NULL (local Computer)
- *  level           [I] Level for the supplied DRIVER_INFO_*W struct
- *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
- *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
- *
- * RESULTS
- *  Success: TRUE
- *  Failure: FALSE
- *
- */
-static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
-{
-    LONG lres;
-
-    TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
-    lres = copy_servername_from_name(pName, NULL);
-    if (lres) {
-        FIXME("server %s not supported\n", debugstr_w(pName));
-        SetLastError(ERROR_ACCESS_DENIED);
-        return FALSE;
-    }
-
-    if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
-        TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
-    }
-
-    return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
-}
-/******************************************************************
- * fpDeleteMonitor [exported through PRINTPROVIDOR]
- *
- * Delete a specific Printmonitor from a Printing-Environment
- *
- * PARAMS
- *  pName        [I] Servername or NULL (local Computer)
- *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
- *  pMonitorName [I] Name of the Monitor, that should be deleted
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE
- *
- * NOTES
- *  pEnvironment is ignored in Windows for the local Computer.
- *
- */
-
-static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
-{
-    HKEY    hroot = NULL;
-    LONG    lres;
-
-    TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
-           debugstr_w(pMonitorName));
-
-    lres = copy_servername_from_name(pName, NULL);
-    if (lres) {
-        FIXME("server %s not supported\n", debugstr_w(pName));
-        SetLastError(ERROR_INVALID_NAME);
-        return FALSE;
-    }
-
-    /*  pEnvironment is ignored in Windows for the local Computer */
-    if (!pMonitorName || !pMonitorName[0]) {
-        TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
-        ERR("unable to create key %s\n", debugstr_w(monitorsW));
-        return FALSE;
-    }
-
-    if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
-        TRACE("%s deleted\n", debugstr_w(pMonitorName));
-        RegCloseKey(hroot);
-        return TRUE;
-    }
-
-    TRACE("%s does not exist\n", debugstr_w(pMonitorName));
-    RegCloseKey(hroot);
-
-    /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
-    SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
-    return FALSE;
-}
-
-/*****************************************************************************
- * fpEnumMonitors [exported through PRINTPROVIDOR]
- *
- * Enumerate available Port-Monitors
- *
- * PARAMS
- *  pName       [I] Servername or NULL (local Computer)
- *  Level       [I] Structure-Level (1:Win9x+NT or 2:NT only)
- *  pMonitors   [O] PTR to Buffer that receives the Result
- *  cbBuf       [I] Size of Buffer at pMonitors
- *  pcbNeeded   [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
- *  pcReturned  [O] PTR to DWORD that receives the number of Monitors in pMonitors
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
- *
- * NOTES
- *  Windows reads the Registry once and cache the Results.
- *
- */
-static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
-                                  LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
-    DWORD   numentries = 0;
-    DWORD   needed = 0;
-    LONG    lres;
-    BOOL    res = FALSE;
-
-    TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
-          cbBuf, pcbNeeded, pcReturned);
-
-    lres = copy_servername_from_name(pName, NULL);
-    if (lres) {
-        FIXME("server %s not supported\n", debugstr_w(pName));
-        SetLastError(ERROR_INVALID_NAME);
-        goto em_cleanup;
-    }
-
-    if (!Level || (Level > 2)) {
-        WARN("level (%d) is ignored in win9x\n", Level);
-        SetLastError(ERROR_INVALID_LEVEL);
-        return FALSE;
-    }
-
-    /* Scan all Monitor-Keys */
-    numentries = 0;
-    needed = get_local_monitors(Level, NULL, 0, &numentries);
-
-    /* we calculated the needed buffersize. now do more error-checks */
-    if (cbBuf < needed) {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-        goto em_cleanup;
-    }
-
-    /* fill the Buffer with the Monitor-Keys */
-    needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
-    res = TRUE;
-
-em_cleanup:
-    if (pcbNeeded)  *pcbNeeded = needed;
-    if (pcReturned) *pcReturned = numentries;
-
-    TRACE("returning %d with %d (%d byte for %d entries)\n",
-            res, GetLastError(), needed, numentries);
-
-    return (res);
-}
-
-/*****************************************************
- *  get_backend [internal]
- */
-static const PRINTPROVIDOR * get_backend(void)
-{
-    static const PRINTPROVIDOR backend = {
-        NULL,   /* fpOpenPrinter */
-        NULL,   /* fpSetJob */
-        NULL,   /* fpGetJob */
-        NULL,   /* fpEnumJobs */
-        NULL,   /* fpAddPrinter */
-        NULL,   /* fpDeletePrinter */
-        NULL,   /* fpSetPrinter */
-        NULL,   /* fpGetPrinter */
-        NULL,   /* fpEnumPrinters */
-        NULL,   /* fpAddPrinterDriver */
-        NULL,   /* fpEnumPrinterDrivers */
-        NULL,   /* fpGetPrinterDriver */
-        fpGetPrinterDriverDirectory,
-        NULL,   /* fpDeletePrinterDriver */
-        NULL,   /* fpAddPrintProcessor */
-        NULL,   /* fpEnumPrintProcessors */
-        NULL,   /* fpGetPrintProcessorDirectory */
-        NULL,   /* fpDeletePrintProcessor */
-        NULL,   /* fpEnumPrintProcessorDatatypes */
-        NULL,   /* fpStartDocPrinter */
-        NULL,   /* fpStartPagePrinter */
-        NULL,   /* fpWritePrinter */
-        NULL,   /* fpEndPagePrinter */
-        NULL,   /* fpAbortPrinter */
-        NULL,   /* fpReadPrinter */
-        NULL,   /* fpEndDocPrinter */
-        NULL,   /* fpAddJob */
-        NULL,   /* fpScheduleJob */
-        NULL,   /* fpGetPrinterData */
-        NULL,   /* fpSetPrinterData */
-        NULL,   /* fpWaitForPrinterChange */
-        NULL,   /* fpClosePrinter */
-        NULL,   /* fpAddForm */
-        NULL,   /* fpDeleteForm */
-        NULL,   /* fpGetForm */
-        NULL,   /* fpSetForm */
-        NULL,   /* fpEnumForms */
-        fpEnumMonitors,
-        NULL,   /* fpEnumPorts */
-        NULL,   /* fpAddPort */
-        NULL,   /* fpConfigurePort */
-        NULL,   /* fpDeletePort */
-        NULL,   /* fpCreatePrinterIC */
-        NULL,   /* fpPlayGdiScriptOnPrinterIC */
-        NULL,   /* fpDeletePrinterIC */
-        NULL,   /* fpAddPrinterConnection */
-        NULL,   /* fpDeletePrinterConnection */
-        NULL,   /* fpPrinterMessageBox */
-        fpAddMonitor,
-        fpDeleteMonitor,
-        NULL,   /* fpResetPrinter */
-        NULL,   /* fpGetPrinterDriverEx */
-        NULL,   /* fpFindFirstPrinterChangeNotification */
-        NULL,   /* fpFindClosePrinterChangeNotification */
-        NULL,   /* fpAddPortEx */
-        NULL,   /* fpShutDown */
-        NULL,   /* fpRefreshPrinterChangeNotification */
-        NULL,   /* fpOpenPrinterEx */
-        NULL,   /* fpAddPrinterEx */
-        NULL,   /* fpSetPort */
-        NULL,   /* fpEnumPrinterData */
-        NULL,   /* fpDeletePrinterData */
-        NULL,   /* fpClusterSplOpen */
-        NULL,   /* fpClusterSplClose */
-        NULL,   /* fpClusterSplIsAlive */
-        NULL,   /* fpSetPrinterDataEx */
-        NULL,   /* fpGetPrinterDataEx */
-        NULL,   /* fpEnumPrinterDataEx */
-        NULL,   /* fpEnumPrinterKey */
-        NULL,   /* fpDeletePrinterDataEx */
-        NULL,   /* fpDeletePrinterKey */
-        NULL,   /* fpSeekPrinter */
-        NULL,   /* fpDeletePrinterDriverEx */
-        NULL,   /* fpAddPerMachineConnection */
-        NULL,   /* fpDeletePerMachineConnection */
-        NULL,   /* fpEnumPerMachineConnections */
-        NULL,   /* fpXcvData */
-        fpAddPrinterDriverEx,
-        NULL,   /* fpSplReadPrinter */
-        NULL,   /* fpDriverUnloadComplete */
-        NULL,   /* fpGetSpoolFileInfo */
-        NULL,   /* fpCommitSpoolData */
-        NULL,   /* fpCloseSpoolFileHandle */
-        NULL,   /* fpFlushPrinter */
-        NULL,   /* fpSendRecvBidiData */
-        NULL    /* fpAddDriverCatalog */
-    };
-    TRACE("=> %p\n", &backend);
-    return &backend;
-
-}
-
 /*****************************************************
  *      DllMain
  */
@@ -1314,40 +49,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls( hinstDLL );
             LOCALSPL_hInstance = hinstDLL;
-            pp = get_backend();
+            setup_provider();
             break;
     }
     return TRUE;
 }
 
-
-/*****************************************************
- * InitializePrintProvidor     (localspl.@)
- *
- * Initialize the Printprovider
- *
- * PARAMS
- *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
- *  cbPrintProvidor   [I] Size of Buffer in Bytes
- *  pFullRegistryPath [I] Registry-Path for the Printprovidor
- *
- * RETURNS
- *  Success: TRUE and pPrintProvidor filled
- *  Failure: FALSE
- *
- * NOTES
- *  The RegistryPath should be:
- *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
- *  but this Parameter is ignored in "localspl.dll".
- *
- */
-
-BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
-                                    DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
-{
-
-    TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
-    memcpy(pPrintProvidor, pp, (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
-
-    return TRUE;
-}
diff --git a/dlls/localspl/localspl_private.h b/dlls/localspl/localspl_private.h
index 8e67ed3..0ac6369 100644
--- a/dlls/localspl/localspl_private.h
+++ b/dlls/localspl/localspl_private.h
@@ -24,6 +24,7 @@
 
 /* ## DLL-wide Globals ## */
 extern HINSTANCE LOCALSPL_hInstance;
+void setup_provider(void);
 
 /* ## Resource-ID ## */
 #define IDS_LOCALPORT       500
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c
new file mode 100644
index 0000000..5fbcd0a
--- /dev/null
+++ b/dlls/localspl/provider.c
@@ -0,0 +1,1327 @@
+/*
+ * Implementation of the Local Printprovider
+ *
+ * Copyright 2006-2009 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winreg.h"
+#include "winspool.h"
+#include "winuser.h"
+#include "ddk/winddiui.h"
+#include "ddk/winsplp.h"
+
+#include "wine/list.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "localspl_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(localspl);
+
+/* ############################### */
+
+static CRITICAL_SECTION monitor_handles_cs;
+static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
+{
+    0, 0, &monitor_handles_cs,
+    { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
+};
+static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
+
+/* ############################### */
+
+typedef struct {
+    WCHAR   src[MAX_PATH+MAX_PATH];
+    WCHAR   dst[MAX_PATH+MAX_PATH];
+    DWORD   srclen;
+    DWORD   dstlen;
+    DWORD   copyflags;
+    BOOL    lazy;
+} apd_data_t;
+
+typedef struct {
+    struct list     entry;
+    LPWSTR          name;
+    LPWSTR          dllname;
+    PMONITORUI      monitorUI;
+    LPMONITOR       monitor;
+    HMODULE         hdll;
+    DWORD           refcount;
+    DWORD           dwMonitorSize;
+} monitor_t;
+
+typedef struct {
+    LPCWSTR  envname;
+    LPCWSTR  subdir;
+    DWORD    driverversion;
+    LPCWSTR  versionregpath;
+    LPCWSTR  versionsubdir;
+} printenv_t;
+
+/* ############################### */
+
+static struct list monitor_handles = LIST_INIT( monitor_handles );
+static monitor_t * pm_localport;
+
+static const PRINTPROVIDOR * pprovider = NULL;
+
+static const WCHAR backslashW[] = {'\\',0};
+static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
+static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
+static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
+static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
+static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
+static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
+static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
+static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
+                                  'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+                                  'c','o','n','t','r','o','l','\\',
+                                  'P','r','i','n','t','\\',
+                                  'E','n','v','i','r','o','n','m','e','n','t','s','\\',
+                                  '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
+static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
+static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
+static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
+static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
+static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
+static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
+static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
+                                'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+                                'C','o','n','t','r','o','l','\\',
+                                'P','r','i','n','t','\\',
+                                'M','o','n','i','t','o','r','s','\\',0};
+static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
+static const WCHAR nameW[] = {'N','a','m','e',0};
+static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
+static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
+static const WCHAR portW[] = {'P','o','r','t',0};
+static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
+static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
+static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
+
+static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
+static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
+static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
+static const WCHAR version0_subdirW[] = {'\\','0',0};
+
+static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
+static const WCHAR x64_subdirW[] = {'x','6','4',0};
+static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
+static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
+static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
+static const WCHAR version3_subdirW[] = {'\\','3',0};
+
+
+static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
+                                     version3_regpathW, version3_subdirW};
+
+static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
+                                     version3_regpathW, version3_subdirW};
+
+static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
+                                     version0_regpathW, version0_subdirW};
+
+static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
+
+
+static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
+                                     sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
+                                     sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
+                                  0, sizeof(DRIVER_INFO_8W)};
+
+
+/******************************************************************
+ * strdupW [internal]
+ *
+ * create a copy of a unicode-string
+ *
+ */
+static LPWSTR strdupW(LPCWSTR p)
+{
+    LPWSTR ret;
+    DWORD len;
+
+    if(!p) return NULL;
+    len = (lstrlenW(p) + 1) * sizeof(WCHAR);
+    ret = heap_alloc(len);
+    memcpy(ret, p, len);
+    return ret;
+}
+
+/******************************************************************
+ *  apd_copyfile [internal]
+ *
+ * Copy a file from the driverdirectory to the versioned directory
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ */
+static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
+{
+    LPWSTR  ptr;
+    LPWSTR  srcname;
+    DWORD   res;
+
+    apd->src[apd->srclen] = '\0';
+    apd->dst[apd->dstlen] = '\0';
+
+    if (!filename || !filename[0]) {
+        /* nothing to copy */
+        return TRUE;
+    }
+
+    ptr = strrchrW(filename, '\\');
+    if (ptr) {
+        ptr++;
+    }
+    else
+    {
+        ptr = filename;
+    }
+
+    if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
+        /* we have an absolute Path */
+        srcname = filename;
+    }
+    else
+    {
+        srcname = apd->src;
+        lstrcatW(srcname, ptr);
+    }
+    lstrcatW(apd->dst, ptr);
+
+    TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
+
+    /* FIXME: handle APD_COPY_NEW_FILES */
+    res = CopyFileW(srcname, apd->dst, FALSE);
+    TRACE("got %u with %u\n", res, GetLastError());
+
+    return (apd->lazy) ? TRUE : res;
+}
+
+/******************************************************************
+ * copy_servername_from_name  (internal)
+ *
+ * for an external server, the serverpart from the name is copied.
+ *
+ * RETURNS
+ *  the length (in WCHAR) of the serverpart (0 for the local computer)
+ *  (-length), when the name is to long
+ *
+ */
+static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
+{
+    LPCWSTR server;
+    LPWSTR  ptr;
+    WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
+    DWORD   len;
+    DWORD   serverlen;
+
+    if (target) *target = '\0';
+
+    if (name == NULL) return 0;
+    if ((name[0] != '\\') || (name[1] != '\\')) return 0;
+
+    server = &name[2];
+    /* skip over both backslash, find separator '\' */
+    ptr = strchrW(server, '\\');
+    serverlen = (ptr) ? ptr - server : lstrlenW(server);
+
+    /* servername is empty or to long */
+    if (serverlen == 0) return 0;
+
+    TRACE("found %s\n", debugstr_wn(server, serverlen));
+
+    if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
+
+    len = sizeof(buffer) / sizeof(buffer[0]);
+    if (GetComputerNameW(buffer, &len)) {
+        if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
+            /* The requested Servername is our computername */
+            if (target) {
+                memcpy(target, server, serverlen * sizeof(WCHAR));
+                target[serverlen] = '\0';
+            }
+            return serverlen;
+        }
+    }
+    return 0;
+}
+
+/******************************************************************
+ * monitor_unload [internal]
+ *
+ * release a printmonitor and unload it from memory, when needed
+ *
+ */
+static void monitor_unload(monitor_t * pm)
+{
+    if (pm == NULL) return;
+    TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
+
+    EnterCriticalSection(&monitor_handles_cs);
+
+    if (pm->refcount) pm->refcount--;
+
+    if (pm->refcount == 0) {
+        list_remove(&pm->entry);
+        FreeLibrary(pm->hdll);
+        heap_free(pm->name);
+        heap_free(pm->dllname);
+        heap_free(pm);
+    }
+    LeaveCriticalSection(&monitor_handles_cs);
+}
+
+/******************************************************************
+ * monitor_load [internal]
+ *
+ * load a printmonitor, get the dllname from the registry, when needed
+ * initialize the monitor and dump found function-pointers
+ *
+ * On failure, SetLastError() is called and NULL is returned
+ */
+
+static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
+{
+    LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
+    PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
+    LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
+    DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
+    DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
+
+    monitor_t * pm = NULL;
+    monitor_t * cursor;
+    LPWSTR  regroot = NULL;
+    LPWSTR  driver = dllname;
+
+    TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
+    /* Is the Monitor already loaded? */
+    EnterCriticalSection(&monitor_handles_cs);
+
+    if (name) {
+        LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
+        {
+            if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
+                pm = cursor;
+                break;
+            }
+        }
+    }
+
+    if (pm == NULL) {
+        pm = heap_alloc_zero(sizeof(monitor_t));
+        if (pm == NULL) goto cleanup;
+        list_add_tail(&monitor_handles, &pm->entry);
+    }
+    pm->refcount++;
+
+    if (pm->name == NULL) {
+        /* Load the monitor */
+        LPMONITOREX pmonitorEx;
+        DWORD   len;
+
+        if (name) {
+            len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
+            regroot = heap_alloc(len * sizeof(WCHAR));
+        }
+
+        if (regroot) {
+            lstrcpyW(regroot, monitorsW);
+            lstrcatW(regroot, name);
+            /* Get the Driver from the Registry */
+            if (driver == NULL) {
+                HKEY    hroot;
+                DWORD   namesize;
+                if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
+                    if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
+                                        &namesize) == ERROR_SUCCESS) {
+                        driver = heap_alloc(namesize);
+                        RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
+                    }
+                    RegCloseKey(hroot);
+                }
+            }
+        }
+
+        pm->name = strdupW(name);
+        pm->dllname = strdupW(driver);
+
+        if ((name && (!regroot || !pm->name)) || !pm->dllname) {
+            monitor_unload(pm);
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            pm = NULL;
+            goto cleanup;
+        }
+
+        pm->hdll = LoadLibraryW(driver);
+        TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
+
+        if (pm->hdll == NULL) {
+            monitor_unload(pm);
+            SetLastError(ERROR_MOD_NOT_FOUND);
+            pm = NULL;
+            goto cleanup;
+        }
+
+        pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
+        pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
+        pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
+        pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
+        pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
+
+
+        TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
+        TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
+        TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
+        TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
+        TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
+
+        if (pInitializePrintMonitorUI  != NULL) {
+            pm->monitorUI = pInitializePrintMonitorUI();
+            TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
+            if (pm->monitorUI) {
+                TRACE("0x%08x: dwMonitorSize (%d)\n",
+                        pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
+
+            }
+        }
+
+        if (pInitializePrintMonitor && regroot) {
+            pmonitorEx = pInitializePrintMonitor(regroot);
+            TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
+                    pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
+
+            if (pmonitorEx) {
+                pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
+                pm->monitor = &(pmonitorEx->Monitor);
+            }
+        }
+
+        if (pm->monitor) {
+            TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
+
+        }
+
+        if (!pm->monitor && regroot) {
+            if (pInitializePrintMonitor2 != NULL) {
+                FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
+            }
+            if (pInitializeMonitorEx != NULL) {
+                FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
+            }
+            if (pInitializeMonitor != NULL) {
+                FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
+            }
+        }
+        if (!pm->monitor && !pm->monitorUI) {
+            monitor_unload(pm);
+            SetLastError(ERROR_PROC_NOT_FOUND);
+            pm = NULL;
+        }
+    }
+cleanup:
+    if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
+        pm->refcount++;
+        pm_localport = pm;
+    }
+    LeaveCriticalSection(&monitor_handles_cs);
+    if (driver != dllname) heap_free(driver);
+    heap_free(regroot);
+    TRACE("=> %p\n", pm);
+    return pm;
+}
+
+/******************************************************************
+ * Return the number of bytes for an multi_sz string.
+ * The result includes all \0s
+ * (specifically the extra \0, that is needed as multi_sz terminator).
+ */
+static int multi_sz_lenW(const WCHAR *str)
+{
+    const WCHAR *ptr = str;
+    if (!str) return 0;
+    do
+    {
+        ptr += lstrlenW(ptr) + 1;
+    } while (*ptr);
+
+    return (ptr - str + 1) * sizeof(WCHAR);
+}
+
+/******************************************************************
+ * validate_envW [internal]
+ *
+ * validate the user-supplied printing-environment
+ *
+ * PARAMS
+ *  env  [I] PTR to Environment-String or NULL
+ *
+ * RETURNS
+ *  Success:  PTR to printenv_t
+ *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
+ *
+ * NOTES
+ *  An empty string is handled the same way as NULL.
+ *
+ */
+
+static const  printenv_t * validate_envW(LPCWSTR env)
+{
+    const printenv_t *result = NULL;
+    unsigned int i;
+
+    TRACE("(%s)\n", debugstr_w(env));
+    if (env && env[0])
+    {
+        for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
+        {
+            if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
+            {
+                result = all_printenv[i];
+                break;
+            }
+        }
+        if (result == NULL) {
+            FIXME("unsupported Environment: %s\n", debugstr_w(env));
+            SetLastError(ERROR_INVALID_ENVIRONMENT);
+        }
+        /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
+    }
+    else
+    {
+        result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
+    }
+
+    TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
+    return result;
+}
+
+/*****************************************************************************
+ * enumerate the local monitors (INTERNAL)
+ *
+ * returns the needed size (in bytes) for pMonitors
+ * and  *lpreturned is set to number of entries returned in pMonitors
+ *
+ * Language-Monitors are also installed in the same Registry-Location but
+ * they are filtered in Windows (not returned by EnumMonitors).
+ * We do no filtering to simplify our Code.
+ *
+ */
+static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
+{
+    HKEY    hroot = NULL;
+    HKEY    hentry = NULL;
+    LPWSTR  ptr;
+    LPMONITOR_INFO_2W mi;
+    WCHAR   buffer[MAX_PATH];
+    WCHAR   dllname[MAX_PATH];
+    DWORD   dllsize;
+    DWORD   len;
+    DWORD   index = 0;
+    DWORD   needed = 0;
+    DWORD   numentries;
+    DWORD   entrysize;
+
+    entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
+
+    numentries = *lpreturned;       /* this is 0, when we scan the registry */
+    len = entrysize * numentries;
+    ptr = (LPWSTR) &pMonitors[len];
+
+    numentries = 0;
+    len = sizeof(buffer)/sizeof(buffer[0]);
+    buffer[0] = '\0';
+
+    /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
+    if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
+        /* Scan all Monitor-Registry-Keys */
+        while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
+            TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
+            dllsize = sizeof(dllname);
+            dllname[0] = '\0';
+
+            /* The Monitor must have a Driver-DLL */
+            if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
+                if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
+                    /* We found a valid DLL for this Monitor. */
+                    TRACE("using Driver: %s\n", debugstr_w(dllname));
+                }
+                RegCloseKey(hentry);
+            }
+
+            /* Windows returns only Port-Monitors here, but to simplify our code,
+               we do no filtering for Language-Monitors */
+            if (dllname[0]) {
+                numentries++;
+                needed += entrysize;
+                needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
+                if (level > 1) {
+                    /* we install and return only monitors for "Windows NT x86" */
+                    needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
+                    needed += dllsize;
+                }
+
+                /* required size is calculated. Now fill the user-buffer */
+                if (pMonitors && (cbBuf >= needed)){
+                    mi = (LPMONITOR_INFO_2W) pMonitors;
+                    pMonitors += entrysize;
+
+                    TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
+                    mi->pName = ptr;
+                    lstrcpyW(ptr, buffer);      /* Name of the Monitor */
+                    ptr += (len+1);               /* len is lstrlenW(monitorname) */
+                    if (level > 1) {
+                        mi->pEnvironment = ptr;
+                        lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
+                        ptr += (lstrlenW(x86_envnameW)+1);
+
+                        mi->pDLLName = ptr;
+                        lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
+                        ptr += (dllsize / sizeof(WCHAR));
+                    }
+                }
+            }
+            index++;
+            len = sizeof(buffer)/sizeof(buffer[0]);
+            buffer[0] = '\0';
+        }
+        RegCloseKey(hroot);
+    }
+    *lpreturned = numentries;
+    TRACE("need %d byte for %d entries\n", needed, numentries);
+    return needed;
+}
+
+/*****************************************************************************
+ * open_driver_reg [internal]
+ *
+ * opens the registry for the printer drivers depending on the given input
+ * variable pEnvironment
+ *
+ * RETURNS:
+ *    Success: the opened hkey
+ *    Failure: NULL
+ */
+static HKEY open_driver_reg(LPCWSTR pEnvironment)
+{
+    HKEY  retval = NULL;
+    LPWSTR buffer;
+    const printenv_t * env;
+
+    TRACE("(%s)\n", debugstr_w(pEnvironment));
+
+    env = validate_envW(pEnvironment);
+    if (!env) return NULL;
+
+    buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
+                (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
+
+    if (buffer) {
+        wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
+        RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
+        HeapFree(GetProcessHeap(), 0, buffer);
+    }
+    return retval;
+}
+
+/*****************************************************************************
+ * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
+ *
+ * Return the PATH for the Printer-Drivers
+ *
+ * PARAMS
+ *   pName            [I] Servername (NT only) or NULL (local Computer)
+ *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
+ *   Level            [I] Structure-Level (must be 1)
+ *   pDriverDirectory [O] PTR to Buffer that receives the Result
+ *   cbBuf            [I] Size of Buffer at pDriverDirectory
+ *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
+ *                        required for pDriverDirectory
+ *
+ * RETURNS
+ *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
+ *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
+ *            if cbBuf is too small
+ *
+ *   Native Values returned in pDriverDirectory on Success:
+ *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
+ *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
+ *|  win9x(Windows 4.0):  "%winsysdir%"
+ *
+ *   "%winsysdir%" is the Value from GetSystemDirectoryW()
+ *
+ */
+static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
+            DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+    DWORD needed;
+    const printenv_t * env;
+
+    TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
+          debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
+
+    if (pName != NULL && pName[0]) {
+        FIXME("server %s not supported\n", debugstr_w(pName));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    env = validate_envW(pEnvironment);
+    if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
+
+
+    /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
+    needed = GetSystemDirectoryW(NULL, 0);
+    /* add the Size for the Subdirectories */
+    needed += lstrlenW(spooldriversW);
+    needed += lstrlenW(env->subdir);
+    needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
+
+    *pcbNeeded = needed;
+
+    if (needed > cbBuf) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return FALSE;
+    }
+
+    if (pDriverDirectory == NULL) {
+        /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+        return FALSE;
+    }
+
+    GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
+    /* add the Subdirectories */
+    lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
+    lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
+
+    TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
+    return TRUE;
+}
+
+/******************************************************************
+ * driver_load [internal]
+ *
+ * load a driver user interface dll
+ *
+ * On failure, NULL is returned
+ *
+ */
+
+static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
+{
+    WCHAR fullname[MAX_PATH];
+    HMODULE hui;
+    DWORD len;
+
+    TRACE("(%p, %s)\n", env, debugstr_w(dllname));
+
+    /* build the driverdir */
+    len = sizeof(fullname) -
+          (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
+
+    if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
+                                     (LPBYTE) fullname, len, &len)) {
+        /* Should never Fail */
+        SetLastError(ERROR_BUFFER_OVERFLOW);
+        return NULL;
+    }
+
+    lstrcatW(fullname, env->versionsubdir);
+    lstrcatW(fullname, backslashW);
+    lstrcatW(fullname, dllname);
+
+    hui = LoadLibraryW(fullname);
+    TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
+
+    return hui;
+}
+
+/******************************************************************************
+ *  myAddPrinterDriverEx [internal]
+ *
+ * Install a Printer Driver with the Option to upgrade / downgrade the Files
+ * and a special mode with lazy error checking.
+ *
+ */
+static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
+{
+    static const WCHAR emptyW[1];
+    const printenv_t *env;
+    apd_data_t apd;
+    DRIVER_INFO_8W di;
+    BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
+    HMODULE hui;
+    LPWSTR  ptr;
+    HKEY    hroot;
+    HKEY    hdrv;
+    DWORD   disposition;
+    DWORD   len;
+    LONG    lres;
+    BOOL    res;
+
+    /* we need to set all entries in the Registry, independent from the Level of
+       DRIVER_INFO, that the caller supplied */
+
+    ZeroMemory(&di, sizeof(di));
+    if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
+        memcpy(&di, pDriverInfo, di_sizeof[level]);
+    }
+
+    /* dump the most used infos */
+    TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
+    TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
+    TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
+    TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
+    TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
+    TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
+    TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
+    /* dump only the first of the additional Files */
+    TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
+
+
+    /* check environment */
+    env = validate_envW(di.pEnvironment);
+    if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
+
+    /* fill the copy-data / get the driverdir */
+    len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
+    if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
+                                    (LPBYTE) apd.src, len, &len)) {
+        /* Should never Fail */
+        return FALSE;
+    }
+    memcpy(apd.dst, apd.src, len);
+    lstrcatW(apd.src, backslashW);
+    apd.srclen = lstrlenW(apd.src);
+    lstrcatW(apd.dst, env->versionsubdir);
+    lstrcatW(apd.dst, backslashW);
+    apd.dstlen = lstrlenW(apd.dst);
+    apd.copyflags = dwFileCopyFlags;
+    apd.lazy = lazy;
+    CreateDirectoryW(apd.src, NULL);
+    CreateDirectoryW(apd.dst, NULL);
+
+    hroot = open_driver_reg(env->envname);
+    if (!hroot) {
+        ERR("Can't create Drivers key\n");
+        return FALSE;
+    }
+
+    /* Fill the Registry for the Driver */
+    if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
+                                KEY_WRITE | KEY_QUERY_VALUE, NULL,
+                                &hdrv, &disposition)) != ERROR_SUCCESS) {
+
+        ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
+        RegCloseKey(hroot);
+        SetLastError(lres);
+        return FALSE;
+    }
+    RegCloseKey(hroot);
+
+    if (disposition == REG_OPENED_EXISTING_KEY) {
+        TRACE("driver %s already installed\n", debugstr_w(di.pName));
+        RegCloseKey(hdrv);
+        SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
+        return FALSE;
+    }
+
+    /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
+    RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
+                   sizeof(DWORD));
+
+    RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
+                   (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
+    apd_copyfile(di.pDriverPath, &apd);
+
+    RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
+                   (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
+    apd_copyfile(di.pDataFile, &apd);
+
+    RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
+                   (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
+    apd_copyfile(di.pConfigFile, &apd);
+
+    /* settings for level 3 */
+    if (di.pHelpFile)
+        RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
+                       (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
+    else
+        RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
+    apd_copyfile(di.pHelpFile, &apd);
+
+
+    ptr = di.pDependentFiles;
+    if (ptr)
+        RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
+                       multi_sz_lenW(di.pDependentFiles));
+    else
+        RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
+    while ((ptr != NULL) && (ptr[0])) {
+        if (apd_copyfile(ptr, &apd)) {
+            ptr += lstrlenW(ptr) + 1;
+        }
+        else
+        {
+            WARN("Failed to copy %s\n", debugstr_w(ptr));
+            ptr = NULL;
+        }
+    }
+    /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
+    if (di.pMonitorName)
+        RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
+                       (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
+    else
+        RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
+
+    if (di.pDefaultDataType)
+        RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
+                       (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
+    else
+        RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
+
+    /* settings for level 4 */
+    if (di.pszzPreviousNames)
+        RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
+                       multi_sz_lenW(di.pszzPreviousNames));
+    else
+        RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
+
+    if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
+
+    RegCloseKey(hdrv);
+    hui = driver_load(env, di.pConfigFile);
+    pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
+    if (hui && pDrvDriverEvent) {
+
+        /* Support for DrvDriverEvent is optional */
+        TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
+        /* MSDN: level for DRIVER_INFO is 1 to 3 */
+        res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
+        TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
+    }
+    FreeLibrary(hui);
+
+    TRACE("=> TRUE with %u\n", GetLastError());
+    return TRUE;
+
+}
+
+/******************************************************************************
+ * fpAddMonitor [exported through PRINTPROVIDOR]
+ *
+ * Install a Printmonitor
+ *
+ * PARAMS
+ *  pName       [I] Servername or NULL (local Computer)
+ *  Level       [I] Structure-Level (Must be 2)
+ *  pMonitors   [I] PTR to MONITOR_INFO_2
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
+ *
+ */
+static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
+{
+    monitor_t * pm = NULL;
+    LPMONITOR_INFO_2W mi2w;
+    HKEY    hroot = NULL;
+    HKEY    hentry = NULL;
+    DWORD   disposition;
+    BOOL    res = FALSE;
+
+    mi2w = (LPMONITOR_INFO_2W) pMonitors;
+    TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
+            debugstr_w(mi2w ? mi2w->pName : NULL),
+            debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
+            debugstr_w(mi2w ? mi2w->pDLLName : NULL));
+
+    if (copy_servername_from_name(pName, NULL)) {
+        FIXME("server %s not supported\n", debugstr_w(pName));
+        SetLastError(ERROR_ACCESS_DENIED);
+        return FALSE;
+    }
+
+    if (!mi2w->pName || (! mi2w->pName[0])) {
+        WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
+        WARN("Environment %s requested (we support only %s)\n",
+                debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
+        SetLastError(ERROR_INVALID_ENVIRONMENT);
+        return FALSE;
+    }
+
+    if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
+        WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* Load and initialize the monitor. SetLastError() is called on failure */
+    if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
+        return FALSE;
+    }
+    monitor_unload(pm);
+
+    if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
+        ERR("unable to create key %s\n", debugstr_w(monitorsW));
+        return FALSE;
+    }
+
+    if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
+                        KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
+                        &disposition) == ERROR_SUCCESS) {
+
+        /* Some installers set options for the port before calling AddMonitor.
+           We query the "Driver" entry to verify that the monitor is installed,
+           before we return an error.
+           When a user installs two print monitors at the same time with the
+           same name, a race condition is possible but silently ignored. */
+
+        DWORD   namesize = 0;
+
+        if ((disposition == REG_OPENED_EXISTING_KEY) &&
+            (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
+                              &namesize) == ERROR_SUCCESS)) {
+            TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
+            /* 9x use ERROR_ALREADY_EXISTS */
+            SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
+        }
+        else
+        {
+            INT len;
+            len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
+            res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
+                    (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
+        }
+        RegCloseKey(hentry);
+    }
+
+    RegCloseKey(hroot);
+    return (res);
+}
+
+/******************************************************************************
+ * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
+ *
+ * Install a Printer Driver with the Option to upgrade / downgrade the Files
+ *
+ * PARAMS
+ *  pName           [I] Servername or NULL (local Computer)
+ *  level           [I] Level for the supplied DRIVER_INFO_*W struct
+ *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
+ *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
+ *
+ * RESULTS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ */
+static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
+{
+    LONG lres;
+
+    TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
+    lres = copy_servername_from_name(pName, NULL);
+    if (lres) {
+        FIXME("server %s not supported\n", debugstr_w(pName));
+        SetLastError(ERROR_ACCESS_DENIED);
+        return FALSE;
+    }
+
+    if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
+        TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
+    }
+
+    return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
+}
+/******************************************************************
+ * fpDeleteMonitor [exported through PRINTPROVIDOR]
+ *
+ * Delete a specific Printmonitor from a Printing-Environment
+ *
+ * PARAMS
+ *  pName        [I] Servername or NULL (local Computer)
+ *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
+ *  pMonitorName [I] Name of the Monitor, that should be deleted
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  pEnvironment is ignored in Windows for the local Computer.
+ *
+ */
+
+static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
+{
+    HKEY    hroot = NULL;
+    LONG    lres;
+
+    TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
+           debugstr_w(pMonitorName));
+
+    lres = copy_servername_from_name(pName, NULL);
+    if (lres) {
+        FIXME("server %s not supported\n", debugstr_w(pName));
+        SetLastError(ERROR_INVALID_NAME);
+        return FALSE;
+    }
+
+    /*  pEnvironment is ignored in Windows for the local Computer */
+    if (!pMonitorName || !pMonitorName[0]) {
+        TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
+        ERR("unable to create key %s\n", debugstr_w(monitorsW));
+        return FALSE;
+    }
+
+    if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
+        TRACE("%s deleted\n", debugstr_w(pMonitorName));
+        RegCloseKey(hroot);
+        return TRUE;
+    }
+
+    TRACE("%s does not exist\n", debugstr_w(pMonitorName));
+    RegCloseKey(hroot);
+
+    /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
+    SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
+    return FALSE;
+}
+
+/*****************************************************************************
+ * fpEnumMonitors [exported through PRINTPROVIDOR]
+ *
+ * Enumerate available Port-Monitors
+ *
+ * PARAMS
+ *  pName      [I] Servername or NULL (local Computer)
+ *  Level      [I] Structure-Level (1:Win9x+NT or 2:NT only)
+ *  pMonitors  [O] PTR to Buffer that receives the Result
+ *  cbBuf      [I] Size of Buffer at pMonitors
+ *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
+ *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
+ *
+ * NOTES
+ *  Windows reads the Registry once and cache the Results.
+ *
+ */
+static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
+                                  LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+    DWORD   numentries = 0;
+    DWORD   needed = 0;
+    LONG    lres;
+    BOOL    res = FALSE;
+
+    TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
+          cbBuf, pcbNeeded, pcReturned);
+
+    lres = copy_servername_from_name(pName, NULL);
+    if (lres) {
+        FIXME("server %s not supported\n", debugstr_w(pName));
+        SetLastError(ERROR_INVALID_NAME);
+        goto em_cleanup;
+    }
+
+    if (!Level || (Level > 2)) {
+        WARN("level (%d) is ignored in win9x\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    /* Scan all Monitor-Keys */
+    numentries = 0;
+    needed = get_local_monitors(Level, NULL, 0, &numentries);
+
+    /* we calculated the needed buffersize. now do more error-checks */
+    if (cbBuf < needed) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        goto em_cleanup;
+    }
+
+    /* fill the Buffer with the Monitor-Keys */
+    needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
+    res = TRUE;
+
+em_cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = numentries;
+
+    TRACE("returning %d with %d (%d byte for %d entries)\n",
+            res, GetLastError(), needed, numentries);
+
+    return (res);
+}
+
+/*****************************************************
+ *  setup_provider [internal]
+ */
+void setup_provider(void)
+{
+    static const PRINTPROVIDOR backend = {
+        NULL,   /* fpOpenPrinter */
+        NULL,   /* fpSetJob */
+        NULL,   /* fpGetJob */
+        NULL,   /* fpEnumJobs */
+        NULL,   /* fpAddPrinter */
+        NULL,   /* fpDeletePrinter */
+        NULL,   /* fpSetPrinter */
+        NULL,   /* fpGetPrinter */
+        NULL,   /* fpEnumPrinters */
+        NULL,   /* fpAddPrinterDriver */
+        NULL,   /* fpEnumPrinterDrivers */
+        NULL,   /* fpGetPrinterDriver */
+        fpGetPrinterDriverDirectory,
+        NULL,   /* fpDeletePrinterDriver */
+        NULL,   /* fpAddPrintProcessor */
+        NULL,   /* fpEnumPrintProcessors */
+        NULL,   /* fpGetPrintProcessorDirectory */
+        NULL,   /* fpDeletePrintProcessor */
+        NULL,   /* fpEnumPrintProcessorDatatypes */
+        NULL,   /* fpStartDocPrinter */
+        NULL,   /* fpStartPagePrinter */
+        NULL,   /* fpWritePrinter */
+        NULL,   /* fpEndPagePrinter */
+        NULL,   /* fpAbortPrinter */
+        NULL,   /* fpReadPrinter */
+        NULL,   /* fpEndDocPrinter */
+        NULL,   /* fpAddJob */
+        NULL,   /* fpScheduleJob */
+        NULL,   /* fpGetPrinterData */
+        NULL,   /* fpSetPrinterData */
+        NULL,   /* fpWaitForPrinterChange */
+        NULL,   /* fpClosePrinter */
+        NULL,   /* fpAddForm */
+        NULL,   /* fpDeleteForm */
+        NULL,   /* fpGetForm */
+        NULL,   /* fpSetForm */
+        NULL,   /* fpEnumForms */
+        fpEnumMonitors,
+        NULL,   /* fpEnumPorts */
+        NULL,   /* fpAddPort */
+        NULL,   /* fpConfigurePort */
+        NULL,   /* fpDeletePort */
+        NULL,   /* fpCreatePrinterIC */
+        NULL,   /* fpPlayGdiScriptOnPrinterIC */
+        NULL,   /* fpDeletePrinterIC */
+        NULL,   /* fpAddPrinterConnection */
+        NULL,   /* fpDeletePrinterConnection */
+        NULL,   /* fpPrinterMessageBox */
+        fpAddMonitor,
+        fpDeleteMonitor,
+        NULL,   /* fpResetPrinter */
+        NULL,   /* fpGetPrinterDriverEx */
+        NULL,   /* fpFindFirstPrinterChangeNotification */
+        NULL,   /* fpFindClosePrinterChangeNotification */
+        NULL,   /* fpAddPortEx */
+        NULL,   /* fpShutDown */
+        NULL,   /* fpRefreshPrinterChangeNotification */
+        NULL,   /* fpOpenPrinterEx */
+        NULL,   /* fpAddPrinterEx */
+        NULL,   /* fpSetPort */
+        NULL,   /* fpEnumPrinterData */
+        NULL,   /* fpDeletePrinterData */
+        NULL,   /* fpClusterSplOpen */
+        NULL,   /* fpClusterSplClose */
+        NULL,   /* fpClusterSplIsAlive */
+        NULL,   /* fpSetPrinterDataEx */
+        NULL,   /* fpGetPrinterDataEx */
+        NULL,   /* fpEnumPrinterDataEx */
+        NULL,   /* fpEnumPrinterKey */
+        NULL,   /* fpDeletePrinterDataEx */
+        NULL,   /* fpDeletePrinterKey */
+        NULL,   /* fpSeekPrinter */
+        NULL,   /* fpDeletePrinterDriverEx */
+        NULL,   /* fpAddPerMachineConnection */
+        NULL,   /* fpDeletePerMachineConnection */
+        NULL,   /* fpEnumPerMachineConnections */
+        NULL,   /* fpXcvData */
+        fpAddPrinterDriverEx,
+        NULL,   /* fpSplReadPrinter */
+        NULL,   /* fpDriverUnloadComplete */
+        NULL,   /* fpGetSpoolFileInfo */
+        NULL,   /* fpCommitSpoolData */
+        NULL,   /* fpCloseSpoolFileHandle */
+        NULL,   /* fpFlushPrinter */
+        NULL,   /* fpSendRecvBidiData */
+        NULL    /* fpAddDriverCatalog */
+    };
+    pprovider = &backend;
+
+}
+
+/*****************************************************
+ * InitializePrintProvidor     (localspl.@)
+ *
+ * Initialize the Printprovider
+ *
+ * PARAMS
+ *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
+ *  cbPrintProvidor   [I] Size of Buffer in Bytes
+ *  pFullRegistryPath [I] Registry-Path for the Printprovidor
+ *
+ * RETURNS
+ *  Success: TRUE and pPrintProvidor filled
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  The RegistryPath should be:
+ *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
+ *  but this Parameter is ignored in "localspl.dll".
+ *
+ */
+
+BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
+                                    DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
+{
+
+    TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
+    memcpy(pPrintProvidor, pprovider,
+          (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
+
+    return TRUE;
+}
-- 
1.5.4.3


--=-at4DOcZN0ds4MSUAQKpW--




More information about the wine-patches mailing list