[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