winspool: Use configuration file for DeviceCapabilitiesW.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2021-09-13 13:48:52 +02:00 committed by Alexandre Julliard
parent a8c4020029
commit afc7c0c9d1
1 changed files with 154 additions and 72 deletions

View File

@ -119,6 +119,7 @@
#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/list.h"
#include "wine/rbtree.h"
#include "wine/heap.h"
#include "winnls.h"
@ -178,6 +179,18 @@ typedef struct {
LPCWSTR versionsubdir;
} printenv_t;
typedef struct
{
struct wine_rb_entry entry;
HMODULE module;
LONG ref;
/* entry points */
DWORD (WINAPI *pDrvDeviceCapabilities)(HANDLE, const WCHAR *, WORD, void *, const DEVMODEW *);
WCHAR name[1];
} config_module_t;
/* ############################### */
static opened_printer_t **printer_handles;
@ -500,6 +513,127 @@ static inline const DWORD *form_string_info( DWORD level )
return NULL;
}
/*****************************************************************************
* WINSPOOL_OpenDriverReg [internal]
*
* opens the registry for the printer drivers depending on the given input
* variable pEnvironment
*
* RETURNS:
* the opened hkey on success
* NULL on error
*/
static HKEY WINSPOOL_OpenDriverReg(const void *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,
(strlenW(DriversW) + strlenW(env->envname) +
strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
if(buffer) {
wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
HeapFree(GetProcessHeap(), 0, buffer);
}
return retval;
}
static CRITICAL_SECTION config_modules_cs;
static CRITICAL_SECTION_DEBUG config_modules_cs_debug =
{
0, 0, &config_modules_cs,
{ &config_modules_cs_debug.ProcessLocksList, &config_modules_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": config_modules_cs") }
};
static CRITICAL_SECTION config_modules_cs = { &config_modules_cs_debug, -1, 0, 0, 0, 0 };
static int compare_config_modules(const void *key, const struct wine_rb_entry *entry)
{
config_module_t *module = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
return lstrcmpiW(key, module->name);
}
static struct wine_rb_tree config_modules = { compare_config_modules };
static void release_config_module(config_module_t *config_module)
{
if (InterlockedDecrement(&config_module->ref)) return;
FreeLibrary(config_module->module);
HeapFree(GetProcessHeap(), 0, config_module);
}
static config_module_t *get_config_module(const WCHAR *device, BOOL grab)
{
WCHAR driver[MAX_PATH];
DWORD size, len;
HKEY driver_key, device_key;
HMODULE driver_module;
config_module_t *ret = NULL;
struct wine_rb_entry *entry;
DWORD type;
LSTATUS res;
EnterCriticalSection(&config_modules_cs);
entry = wine_rb_get(&config_modules, device);
if (entry) {
ret = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
if (grab) InterlockedIncrement(&ret->ref);
goto ret;
}
if (!grab) goto ret;
if (!(driver_key = WINSPOOL_OpenDriverReg(NULL))) goto ret;
res = RegOpenKeyW(driver_key, device, &device_key);
RegCloseKey(driver_key);
if (res) {
WARN("Device %s key not found\n", debugstr_w(device));
goto ret;
}
size = sizeof(driver);
if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (LPBYTE)driver, size, &size)) goto ret;
len = size / sizeof(WCHAR) - 1;
driver[len++] = '\\';
driver[len++] = '3';
driver[len++] = '\\';
size = sizeof(driver) - len * sizeof(WCHAR);
res = RegQueryValueExW(device_key, Configuration_FileW, NULL, &type,
(BYTE *)(driver + len), &size);
RegCloseKey(device_key);
if (res || type != REG_SZ) {
WARN("no configuration file: %u\n", res);
goto ret;
}
if (!(driver_module = LoadLibraryW(driver))) {
WARN("Could not load %s\n", debugstr_w(driver));
goto ret;
}
len = lstrlenW(device);
if (!(ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(config_module_t, name[len + 1]))))
goto ret;
ret->ref = 2; /* one for config_module and one for the caller */
ret->module = driver_module;
ret->pDrvDeviceCapabilities = (void *)GetProcAddress(driver_module, "DrvDeviceCapabilities");
lstrcpyW(ret->name, device);
wine_rb_put(&config_modules, ret->name, &ret->entry);
ret:
LeaveCriticalSection(&config_modules_cs);
return ret;
}
/******************************************************************
* verify, that the filename is a local file
*
@ -2361,57 +2495,28 @@ INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
return ret;
}
/*****************************************************************************
* DeviceCapabilitiesW [WINSPOOL.@]
*
* Call DeviceCapabilitiesA since we later call 16bit stuff anyway
*
*/
INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
WORD fwCapability, LPWSTR pOutput,
const DEVMODEW *pDevMode)
{
LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
LPSTR pDeviceA = strdupWtoA(pDevice);
LPSTR pPortA = strdupWtoA(pPort);
INT ret;
config_module_t *config;
int ret;
TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability,
pOutput, pDevMode);
if(pOutput && (fwCapability == DC_BINNAMES ||
fwCapability == DC_FILEDEPENDENCIES ||
fwCapability == DC_PAPERNAMES)) {
/* These need A -> W translation */
INT size = 0, i;
LPSTR pOutputA;
ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
dmA);
if(ret == -1)
return ret;
switch(fwCapability) {
case DC_BINNAMES:
size = 24;
break;
case DC_PAPERNAMES:
case DC_FILEDEPENDENCIES:
size = 64;
break;
}
pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
dmA);
for(i = 0; i < ret; i++)
MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
pOutput + (i * size), size);
HeapFree(GetProcessHeap(), 0, pOutputA);
} else {
ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
(LPSTR)pOutput, dmA);
if (!(config = get_config_module(pDevice, TRUE))) {
WARN("Could not load config module for %s\n", debugstr_w(pDevice));
return 0;
}
HeapFree(GetProcessHeap(),0,pPortA);
HeapFree(GetProcessHeap(),0,pDeviceA);
HeapFree(GetProcessHeap(),0,dmA);
ret = config->pDrvDeviceCapabilities(NULL /* FIXME */, pDevice, fwCapability,
pOutput, pDevMode);
release_config_module(config);
return ret;
}
@ -3186,38 +3291,6 @@ BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
}
/*****************************************************************************
* WINSPOOL_OpenDriverReg [internal]
*
* opens the registry for the printer drivers depending on the given input
* variable pEnvironment
*
* RETURNS:
* the opened hkey on success
* NULL on error
*/
static HKEY WINSPOOL_OpenDriverReg( LPCVOID 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,
(strlenW(DriversW) + strlenW(env->envname) +
strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
if(buffer) {
wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
HeapFree(GetProcessHeap(), 0, buffer);
}
return retval;
}
/*****************************************************************************
* set_devices_and_printerports [internal]
*
@ -3499,6 +3572,7 @@ BOOL WINAPI DeleteFormW( HANDLE printer, WCHAR *name )
BOOL WINAPI DeletePrinter(HANDLE hPrinter)
{
LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
config_module_t *config_module;
HKEY hkeyPrinters, hkey;
WCHAR def[MAX_PATH];
DWORD size = ARRAY_SIZE(def);
@ -3507,6 +3581,14 @@ BOOL WINAPI DeletePrinter(HANDLE hPrinter)
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
EnterCriticalSection(&config_modules_cs);
if ((config_module = get_config_module(lpNameW, FALSE))) {
wine_rb_remove(&config_modules, &config_module->entry);
release_config_module(config_module);
}
LeaveCriticalSection(&config_modules_cs);
if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
RegDeleteTreeW(hkeyPrinters, lpNameW);
RegCloseKey(hkeyPrinters);