From 5df0dc5846e194d4cc8b2e8773f4d6272c4bf31b Mon Sep 17 00:00:00 2001 From: Detlef Riekenberg Date: Fri, 8 Feb 2008 00:39:49 +0100 Subject: [PATCH] localspl: Implement fpAddPrinterDriverEx. --- dlls/localspl/localspl_main.c | 375 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 373 insertions(+), 2 deletions(-) diff --git a/dlls/localspl/localspl_main.c b/dlls/localspl/localspl_main.c index f8556356931..3cb477e5999 100644 --- a/dlls/localspl/localspl_main.c +++ b/dlls/localspl/localspl_main.c @@ -29,8 +29,10 @@ #include "winreg.h" #include "winspool.h" #include "ddk/winsplp.h" +#include "winuser.h" #include "wine/debug.h" +#include "wine/unicode.h" #include "localspl_private.h" WINE_DEFAULT_DEBUG_CHANNEL(localspl); @@ -38,6 +40,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(localspl); /* ############################### */ 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 { LPCWSTR envname; LPCWSTR subdir; DWORD driverversion; @@ -52,7 +63,33 @@ 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 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 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}; @@ -73,6 +110,131 @@ static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0, static const printenv_t * const all_printenv[] = {&env_x86, &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)}; + +/****************************************************************** + * 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 seperator '\' */ + 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; +} + +/****************************************************************** + * 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] * @@ -122,6 +284,38 @@ static const printenv_t * validate_envW(LPCWSTR env) } /***************************************************************************** + * 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 @@ -148,7 +342,7 @@ static const printenv_t * validate_envW(LPCWSTR env) * "%winsysdir%" is the Value from GetSystemDirectoryW() * */ -BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment, +static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD needed; @@ -196,6 +390,183 @@ BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment, return TRUE; } +/****************************************************************************** + * myAddPrinterDriverEx [internal] + * + * Install a Printer Driver with the Option to upgrade / downgrade the Files + * and a special mode with lazy error ckecking + * + */ +static BOOL WINAPI myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy) +{ + const printenv_t *env; + apd_data_t apd; + DRIVER_INFO_8W di; + LPWSTR ptr; + HKEY hroot; + HKEY hdrv; + DWORD disposition; + DWORD len; + LONG lres; + + /* 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 */ + 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 by the caller 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) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName)); + + RegCloseKey(hdrv); + TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n"); + + TRACE("=> TRUE with %u\n", GetLastError()); + return TRUE; + +} + +/****************************************************************************** + * 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); +} + /***************************************************** * get_backend [internal] */ @@ -279,7 +650,7 @@ static const PRINTPROVIDOR * get_backend(void) NULL, /* fpDeletePerMachineConnection */ NULL, /* fpEnumPerMachineConnections */ NULL, /* fpXcvData */ - NULL, /* fpAddPrinterDriverEx */ + fpAddPrinterDriverEx, NULL, /* fpSplReadPrinter */ NULL, /* fpDriverUnloadComplete */ NULL, /* fpGetSpoolFileInfo */ -- 2.11.4.GIT