winspool: [1/2] Implement AddPrinterDriverExW

Detlef Riekenberg wine.dev at web.de
Wed Aug 15 22:29:31 CDT 2007


This is for bug 9273.


Changelog:
winspool: Implement AddPrinterDriverExW


-- 
 
By by ... Detlef

-------------- next part --------------
>From 136e781330be01a92d1aceb7929f28f7f2170814 Mon Sep 17 00:00:00 2001
From: Detlef Riekenberg <wine.dev at web.de>
Date: Wed, 15 Aug 2007 23:30:59 +0200
Subject: [PATCH] winspool: implement AddPrinterDriverExW
---
 dlls/winspool.drv/info.c |  266 ++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 257 insertions(+), 9 deletions(-)

diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 35c4a27..fd57924 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -86,6 +86,14 @@ static CRITICAL_SECTION printer_handles_
 /* ############################### */
 
 typedef struct {
+    WCHAR   src[MAX_PATH+MAX_PATH];
+    WCHAR   dst[MAX_PATH+MAX_PATH];
+    DWORD   srclen;
+    DWORD   dstlen;
+    DWORD   copyflags;
+} apd_data_t;
+
+typedef struct {
     struct list     entry;
     LPWSTR          name;
     LPWSTR          dllname;
@@ -227,6 +235,7 @@ static const WCHAR PrinterDriverDataW[] 
 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
+static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
 static const WCHAR deviceW[]  = {'d','e','v','i','c','e',0};
 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
@@ -343,8 +352,82 @@ static LPSTR strdupWtoA( LPCWSTR str )
     return ret;
 }
 
-/* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
-   The result includes all \0s (specifically the last two). */
+/******************************************************************
+ *  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());
+
+    /* FIXME: install of wineps.drv must be fixed, before we return the real result 
+    return res;
+    */
+    return TRUE;
+}
+
+
+/******************************************************************
+ * 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);
+}
+
+/* ################################ */
+
 static int multi_sz_lenA(const char *str)
 {
     const char *ptr = str;
@@ -6375,15 +6458,180 @@ BOOL WINAPI AddPrinterConnectionW( LPWST
 }
 
 /******************************************************************************
- *		AddPrinterDriverExW (WINSPOOL.@)
+ *  AddPrinterDriverExW (WINSPOOL.@)
+ *
+ * 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
+ *
  */
-BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
-    LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
+BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
 {
-    FIXME("%s %d %p %d\n", debugstr_w(pName),
-           Level, pDriverInfo, dwFileCopyFlags);
-    SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
-    return FALSE;
+    const printenv_t *env;
+    apd_data_t apd;
+    DRIVER_INFO_8W di;
+    LPWSTR  ptr;
+    HKEY    hroot;
+    HKEY    hdrv;
+    DWORD   disposition;
+    DWORD   len;
+    LONG    lres;
+
+    TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
+
+    if (level < 2 || level == 5 || level == 7 || level > 8) {
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    if (!pDriverInfo) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
+        FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
+    }
+
+    ptr = get_servername_from_name(pName);
+    HeapFree(GetProcessHeap(), 0, ptr);
+    if (ptr) {
+        FIXME("not suported for server: %s\n", debugstr_w(pName));
+        SetLastError(ERROR_ACCESS_DENIED);
+        return FALSE;
+    }
+
+    /* 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 (!GetPrinterDriverDirectoryW(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;
+    CreateDirectoryW(apd.src, NULL);
+    CreateDirectoryW(apd.dst, NULL);
+
+    /* Fill the Registry for the Driver */
+    hroot = WINSPOOL_OpenDriverReg(env->envname, TRUE);
+    if(!hroot) {
+        ERR("Can't create Drivers key\n");
+        return FALSE;
+    }
+
+    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 */
+    RegSetValueExW(hdrv, Help_FileW, 0, REG_SZ, (LPBYTE) di.pHelpFile, 
+                   di.pHelpFile ? (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR) : 0);
+    apd_copyfile(di.pHelpFile, &apd);
+
+
+    ptr = di.pDependentFiles;
+    RegSetValueExW(hdrv, Dependent_FilesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles, 
+                   di.pDependentFiles ? multi_sz_lenW(di.pDependentFiles) : 0);
+    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 to "%SystemRoot%\system32" */
+    RegSetValueExW(hdrv, MonitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName, 
+                   di.pMonitorName ? (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR) : 0);
+
+    RegSetValueExW(hdrv, DatatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType, 
+                   di.pDefaultDataType ? (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR) : 0);
+
+    /* settings for level 4 */
+    RegSetValueExW(hdrv, Previous_NamesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames, 
+                   di.pszzPreviousNames ? multi_sz_lenW(di.pszzPreviousNames) : 0);
+
+    if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
+
+
+    RegCloseKey(hdrv);
+    FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
+
+
+    TRACE("=> TRUE with %u\n", GetLastError());
+    return TRUE;
+
 }
 
 /******************************************************************************
-- 
1.4.1



More information about the wine-patches mailing list