[winspool 4/6] Obtain the correct PPD file at driver creation, and copy it into the correct driver directory.

Jeremy White jwhite at codeweavers.com
Wed Dec 23 14:20:55 CST 2009


---
 dlls/winspool.drv/info.c       |  205 +++++++++++++++++++++++++++++++++++++++-
 dlls/winspool.drv/tests/info.c |    1 -
 2 files changed, 202 insertions(+), 4 deletions(-)

diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 7a0dfe3..936599e 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -468,6 +468,160 @@ static char * WINSPOOL_GetPPDName(const printenv_t *env, const char *name)
     return ppdFileName;
 }
 
+/*****************************************************************************
+ *          WINSPOOL_CopyPPD [internal]
+ *
+ *    Make sure PPD file for a driver is copied into the printer driver directory
+ *
+ */
+static void WINSPOOL_CopyPPD(const printenv_t *env, const char *name)
+{
+    DWORD needed;
+    DWORD ppdType = REG_SZ;
+    DWORD rc;
+    char *out_ppd = WINSPOOL_GetPPDName(env, name);
+    char *in_ppd = NULL;
+    BOOL  unlink = FALSE;
+
+    TRACE("(%s)\n", name);
+
+    if (! out_ppd)
+    {
+        ERR("Could not get PPD location for printer %s\n", name);
+        return;
+    }
+
+#ifdef SONAME_LIBCUPS
+    /* We prefer to get the name from CUPS */
+    if (pcupsGetPPD)
+    {
+        const char *ppd = pcupsGetPPD(name);
+        if (ppd)
+        {
+            in_ppd = strdup(ppd);
+            unlink = TRUE;
+        }
+        else
+            WARN("CUPS: Did not find ppd for %s\n", name);
+
+    }
+    else
+        ERR("Could not dlsym cupsGetPPD\n");
+#endif
+
+    if (! in_ppd)
+    {
+        /* Try HKLM\System\CurentControlSet\Control\Print\Printers\@PRINTER@\PrinterDriverData\PPD File */
+
+        HKEY hkeyPrinters, hkeyPrinter, hkeySubkey;
+
+        TRACE("CUPS failed, trying PrinterDriverData registry key\n");
+
+        rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
+        if (rc == ERROR_SUCCESS)
+        {
+            rc = RegOpenKeyA(hkeyPrinters, name, &hkeyPrinter);
+            if (rc == ERROR_SUCCESS)
+            {
+                rc = RegOpenKeyA(hkeyPrinter, "PrinterDriverData", &hkeySubkey);
+                if (rc == ERROR_SUCCESS)
+                {
+                    rc = RegQueryValueExA(hkeySubkey, "PPD File", 0, &ppdType, NULL, &needed);
+                    if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
+                    {
+                        in_ppd = HeapAlloc(GetProcessHeap(), 0, needed);
+                        rc = RegQueryValueExA(hkeySubkey, "PPD File", 0, &ppdType, (LPBYTE) in_ppd, &needed);
+                        if (rc != ERROR_SUCCESS)
+                        {
+                            HeapFree(GetProcessHeap(), 0, in_ppd);
+                            in_ppd = NULL;
+                        }
+                    }
+                    RegCloseKey(hkeySubkey);
+                }
+                RegCloseKey(hkeyPrinter);
+            }
+            RegCloseKey(hkeyPrinters);
+        }
+    }
+
+    if (! in_ppd)
+    {
+        /* Try HKCU\Software\Wine\Printing\PPD Files */
+        HKEY hkey;
+
+        TRACE("PrinterDriverData registry key failed; trying Software\\Wine\\Printing\\PPD Files\n");
+
+        rc = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files", &hkey);
+        if (rc == ERROR_SUCCESS)
+        {
+            const char * value_name = NULL;
+
+            if (RegQueryValueExA(hkey, name, 0, NULL, NULL, &needed) == ERROR_SUCCESS)
+                value_name = name;
+            else if (RegQueryValueExA(hkey, "generic", 0, NULL, NULL, &needed) == ERROR_SUCCESS)
+                value_name = "generic";
+
+            if (value_name)
+            {
+                in_ppd = HeapAlloc(GetProcessHeap(), 0, needed);
+                rc = RegQueryValueExA(hkey, value_name, 0, &ppdType, (LPBYTE)in_ppd, &needed);
+                if (rc != ERROR_SUCCESS)
+                {
+                    HeapFree(GetProcessHeap(), 0, in_ppd);
+                    in_ppd = NULL;
+                }
+            }
+            RegCloseKey(hkey);
+        }
+    }
+
+    if (!in_ppd)
+    {
+        /* Try to find an installed generic.ppd, or one in the wine source tree */
+        const char *data_dir;
+        const char *filename = NULL;
+
+        TRACE("Software\\Wine\\Printing\\PPD Files failed, trying generic.ppd\n");
+
+        if ((data_dir = wine_get_data_dir()))
+            filename = "/generic.ppd";
+        else if ((data_dir = wine_get_build_dir()))
+            filename = "/dlls/wineps.drv/generic.ppd";
+
+        if (filename)
+        {
+            in_ppd = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1);
+            strcpy(in_ppd, data_dir);
+            strcat(in_ppd, filename);
+        }
+    }
+
+    if (in_ppd && ppdType == REG_EXPAND_SZ)
+    {
+        char *tmp;
+        needed = ExpandEnvironmentStringsA(in_ppd, NULL, 0);
+        tmp = HeapAlloc(GetProcessHeap(), 0, needed);
+        ExpandEnvironmentStringsA(in_ppd, tmp, needed);
+        HeapFree(GetProcessHeap(), 0, in_ppd);
+        in_ppd = tmp;
+    }
+
+    if (in_ppd)
+    {
+        if (unlink)
+            MoveFileExA(in_ppd, out_ppd, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
+        else
+            CopyFileA(in_ppd, out_ppd, FALSE);
+    }
+    else
+        WARN("Could not find *any* ppd for %s\n", name);
+
+    HeapFree(GetProcessHeap(), 0, in_ppd);
+    HeapFree(GetProcessHeap(), 0, out_ppd);
+}
+
+
 static BOOL is_driver_directory_missing(const printenv_t *env)
 {
     char *buf, *p;
@@ -510,6 +664,40 @@ static void create_driver_directories(void)
     }
 }
 
+static void repair_ppds(void)
+{
+    int i, j;
+    HKEY hkeyDrivers, hkey;
+    DWORD num, maxlen;
+
+    WARN("Detected old WINEPREFIX, upgrading PPD file values\n");
+
+    create_driver_directories();
+
+    for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
+    {
+        hkeyDrivers = WINSPOOL_OpenDriverReg(all_printenv[i]->envname);
+        if (RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &num, &maxlen, NULL,
+                            NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+        {
+            char *driver_name = HeapAlloc(GetProcessHeap(), 0, maxlen + 1);
+            for (j = 0; j < num; j++)
+            {
+                if(RegEnumKeyA(hkeyDrivers, j, driver_name, maxlen + 1) == ERROR_SUCCESS)
+                    if(RegOpenKeyA(hkeyDrivers, driver_name, &hkey) == ERROR_SUCCESS)
+                    {
+                        char *ppd_path = WINSPOOL_GetPPDName(all_printenv[i], driver_name);
+                        WINSPOOL_CopyPPD(all_printenv[i], driver_name);
+                        RegSetValueExA(hkey, "Data File", 0, REG_SZ, (LPBYTE) ppd_path, strlen(ppd_path) + 1);
+                        HeapFree(GetProcessHeap(), 0, ppd_path);
+                    }
+            }
+            HeapFree(GetProcessHeap(), 0, driver_name);
+        }
+    }
+
+}
+
 static BOOL add_printer_driver(const char *name)
 {
     DRIVER_INFO_3A di3a;
@@ -518,7 +706,6 @@ static BOOL add_printer_driver(const char *name)
                 driver_nt[]         = "wineps.drv",
                 env_9x[]            = "Windows 4.0",
                 env_nt[]            = "Windows NT x86",
-                data_file[]         = "generic.ppd",
                 default_data_type[] = "RAW";
 
     ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
@@ -526,9 +713,10 @@ static BOOL add_printer_driver(const char *name)
     di3a.pName            = (char *)name;
     di3a.pEnvironment     = env_nt;
     di3a.pDriverPath      = driver_nt;
-    di3a.pDataFile        = data_file;
+    di3a.pDataFile        = WINSPOOL_GetPPDName(NULL, name);
     di3a.pConfigFile      = driver_nt;
     di3a.pDefaultDataType = default_data_type;
+    WINSPOOL_CopyPPD(&env_x86, name);
 
     if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
         (GetLastError() ==  ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
@@ -537,14 +725,17 @@ static BOOL add_printer_driver(const char *name)
         di3a.pEnvironment = env_9x;
         di3a.pDriverPath  = driver_9x;
         di3a.pConfigFile  = driver_9x;
+        WINSPOOL_CopyPPD(&env_win40, name);
         if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
             (GetLastError() ==  ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
         {
+            HeapFree(GetProcessHeap(), 0, di3a.pDataFile);
             return TRUE;
         }
     }
     ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
         debugstr_a(di3a.pEnvironment), GetLastError());
+    HeapFree(GetProcessHeap(), 0, di3a.pDataFile);
     return FALSE;
 }
 
@@ -1146,10 +1337,18 @@ void WINSPOOL_LoadSystemPrinters(void)
         HeapFree(GetProcessHeap(), 0, pi);
     }
 
+#ifdef SONAME_LIBCUPS
+    done = CUPS_LoadLibrary();
+#endif
+
+    /* Test for and correct pre Wine 1.1.34 PPD files */
+    if (num > 0 && is_driver_directory_missing(&env_x86))
+        repair_ppds();
+
     create_driver_directories();
 
 #ifdef SONAME_LIBCUPS
-    if (CUPS_LoadLibrary())
+    if (done)
         done = CUPS_LoadPrinters();
 #endif
 
diff --git a/dlls/winspool.drv/tests/info.c b/dlls/winspool.drv/tests/info.c
index f3b2d78..070c8ef 100644
--- a/dlls/winspool.drv/tests/info.c
+++ b/dlls/winspool.drv/tests/info.c
@@ -2403,7 +2403,6 @@ static void test_GetPrinterDriver(void)
             hf = CreateFileA(di_2->pDataFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
             if(hf != INVALID_HANDLE_VALUE)
                 CloseHandle(hf);
-            todo_wine
             ok(hf != INVALID_HANDLE_VALUE, "Could not open %s\n", di_2->pDataFile);
 
             hf = CreateFileA(di_2->pConfigFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);



More information about the wine-patches mailing list