[APPHELP] Initial implementation of ApphelpCheckRunAppEx. CORE-10368

svn path=/trunk/; revision=74601
This commit is contained in:
Mark Jansen 2017-05-19 20:13:08 +00:00
parent a9757a1ab0
commit bbe72b0163
4 changed files with 410 additions and 62 deletions

View file

@ -1,7 +1,7 @@
/*
* Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blažević
* Copyright 2015 Mark Jansen
* Copyright 2015-2017 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,8 +24,9 @@
#include "winver.h"
#include "strsafe.h"
#include "apphelp.h"
#include "ndk/rtlfuncs.h"
#include "ndk/kdtypes.h"
#include "wine/winternl.h"
/* from dpfilter.h */
#define DPFLTR_APPCOMPAT_ID 123
@ -35,23 +36,19 @@
#endif
ULONG g_ShimDebugLevel = 0xffffffff;
HMODULE g_hInstance;
void ApphelppInitDebugLevel(void)
{
UNICODE_STRING DebugKey, DebugValue;
static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
UNICODE_STRING DebugValue;
NTSTATUS Status;
ULONG NewLevel = SHIM_ERR;
WCHAR Buffer[40];
RtlInitUnicodeString(&DebugKey, L"SHIM_DEBUG_LEVEL");
DebugValue.MaximumLength = sizeof(Buffer);
DebugValue.Buffer = Buffer;
DebugValue.Length = 0;
RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
/* Hold the lock as short as possible. */
RtlAcquirePebLock();
Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
RtlReleasePebLock();
if (NT_SUCCESS(Status))
{
@ -61,6 +58,7 @@ void ApphelppInitDebugLevel(void)
g_ShimDebugLevel = NewLevel;
}
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
switch (reason)
@ -70,6 +68,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
return FALSE; /* prefer native version */
#endif
case DLL_PROCESS_ATTACH:
g_hInstance = hinst;
DisableThreadLibraryCalls( hinst );
SdbpHeapInit();
break;
@ -145,9 +144,11 @@ BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format
break;
}
StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName);
va_start(ArgList, Format);
StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
va_end(ArgList);
#if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
#else
@ -156,3 +157,102 @@ BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format
#endif
}
#define APPHELP_DONTWRITE_REASON 2
#define APPHELP_CLEARBITS 0x100 /* TODO: Investigate */
#define APPHELP_IGNORE_ENVIRONMENT 0x400
#define APPHELP_VALID_RESULT 0x10000
#define APPHELP_RESULT_NOTFOUND 0x20000
#define APPHELP_RESULT_FOUND 0x40000
/**
* Lookup Shims / Fixes for the specified application
*
* @param [in] FileHandle Handle to the file to check.
* @param [in] Unk1
* @param [in] Unk2
* @param [in] ApplicationName Exe to check
* @param [in] Environment The environment variables to use, or NULL to use the current environment.
* @param [in] ExeType Exe type (MACHINE_TYPE_XXXX)
* @param [in,out] Reason Input/output flags
* @param [in] SdbQueryAppCompatData The resulting data.
* @param [in] SdbQueryAppCompatDataSize The resulting data size.
* @param [in] SxsData TODO
* @param [in] SxsDataSize TODO
* @param [in] FusionFlags TODO
* @param [in] SomeFlag1 TODO
* @param [in] SomeFlag2 TODO
*
* @return TRUE if the application is allowed to run.
*/
BOOL
WINAPI
ApphelpCheckRunAppEx(
_In_ HANDLE FileHandle,
_In_opt_ PVOID Unk1,
_In_opt_ PVOID Unk2,
_In_opt_z_ PWCHAR ApplicationName,
_In_opt_ PVOID Environment,
_In_opt_ USHORT ExeType,
_Inout_opt_ PULONG Reason,
_Out_opt_ PVOID* SdbQueryAppCompatData,
_Out_opt_ PULONG SdbQueryAppCompatDataSize,
_Out_opt_ PVOID* SxsData,
_Out_opt_ PULONG SxsDataSize,
_Out_opt_ PULONG FusionFlags,
_Out_opt_ PULONG64 SomeFlag1,
_Out_opt_ PULONG SomeFlag2)
{
SDBQUERYRESULT* result = NULL;
HSDB hsdb = NULL;
DWORD dwFlags = 0;
if (SxsData)
*SxsData = NULL;
if (SxsDataSize)
*SxsDataSize = 0;
if (FusionFlags)
*FusionFlags = 0;
if (SomeFlag1)
*SomeFlag1 = 0;
if (SomeFlag2)
*SomeFlag2 = 0;
if (Reason)
dwFlags = *Reason;
dwFlags &= ~APPHELP_CLEARBITS;
*SdbQueryAppCompatData = result = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SDBQUERYRESULT));
if (SdbQueryAppCompatDataSize)
*SdbQueryAppCompatDataSize = sizeof(*result);
hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
if (hsdb)
{
BOOL FoundMatch;
DWORD MatchingExeFlags = 0;
if (dwFlags & APPHELP_IGNORE_ENVIRONMENT)
MatchingExeFlags |= SDBGMEF_IGNORE_ENVIRONMENT;
FoundMatch = SdbGetMatchingExe(hsdb, ApplicationName, NULL, Environment, MatchingExeFlags, result);
if (FileHandle != INVALID_HANDLE_VALUE)
{
dwFlags |= APPHELP_VALID_RESULT;
dwFlags |= (FoundMatch ? APPHELP_RESULT_FOUND : APPHELP_RESULT_NOTFOUND);
}
SdbReleaseDatabase(hsdb);
}
if (Reason && !(dwFlags & APPHELP_DONTWRITE_REASON))
*Reason = dwFlags;
/* We should _ALWAYS_ return TRUE here, unless we want to block an application from starting! */
return TRUE;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright 2013 Mislav Blažević
* Copyright 2015,2016 Mark Jansen
* Copyright 2015-2017 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -63,6 +63,10 @@ typedef struct tagATTRINFO {
#define SHIMREG_DISABLE_LAYER (0x00000020)
#define SHIMREG_DISABLE_DRIVER (0x00000040)
/* Flags for dwFlags */
#define SHIMREG_HAS_ENVIRONMENT (0x1)
/* Flags for SdbGetMatchingExe */
#define SDBGMEF_IGNORE_ENVIRONMENT (0x1)
typedef struct tagSDBQUERYRESULT {
@ -100,6 +104,7 @@ TAG WINAPI SdbGetTagFromTagID(PDB db, TAGID tagid);
TAGID WINAPI SdbFindFirstTag(PDB db, TAGID parent, TAG tag);
TAGID WINAPI SdbFindNextTag(PDB db, TAGID parent, TAGID prev_child);
BOOL WINAPI SdbGetDatabaseID(PDB db, GUID* Guid);
DWORD WINAPI SdbReadDWORDTag(PDB db, TAGID tagid, DWORD ret);
/* sdbfileattr.c*/
BOOL WINAPI SdbFreeFileAttributes(PATTRINFO attr_info);
@ -110,6 +115,7 @@ BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwByte
BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable);
/* hsdb.c */
BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name, LPCWSTR env, DWORD flags, PSDBQUERYRESULT result);
BOOL WINAPI SdbTagIDToTagRef(HSDB hsdb, PDB pdb, TAGID tiWhich, TAGREF* ptrWhich);

View file

@ -3,7 +3,7 @@
@ stdcall ApphelpCheckInstallShieldPackage(ptr wstr)
@ stub ApphelpCheckMsiPackage
@ stub ApphelpCheckRunApp
@ stub ApphelpCheckRunAppEx
@ stdcall ApphelpCheckRunAppEx(ptr ptr ptr wstr ptr long ptr ptr ptr ptr ptr ptr ptr ptr)
@ stdcall ApphelpCheckShellObject(ptr long ptr)
@ stub ApphelpCreateAppcompatData
@ stub ApphelpFixMsiPackage

View file

@ -1,7 +1,7 @@
/*
* Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blažević
* Copyright 2015,2016 Mark Jansen
* Copyright 2015-2017 Mark Jansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -26,6 +26,9 @@
#include "wine/unicode.h"
#define MAX_LAYER_LENGTH 256
#define GPLK_USER 1
#define GPLK_MACHINE 2
static BOOL WINAPI SdbpFileExists(LPCWSTR path)
{
@ -33,6 +36,205 @@ static BOOL WINAPI SdbpFileExists(LPCWSTR path)
return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
}
static BOOL WINAPI SdbpMatchExe(PDB db, TAGID exe, WCHAR* dir)
{
static const WCHAR fmt[] = {'%','s','%','s',0};
WCHAR buffer[256]; /* FIXME: rewrite using a buffer that can grow if needed, f.e. RtlInitBuffer stuff! */
TAGID matching_file;
/* TODO: check size/checksum from the main exe as well as from the extra files */
for (matching_file = SdbFindFirstTag(db, exe, TAG_MATCHING_FILE);
matching_file != TAGID_NULL; matching_file = SdbFindNextTag(db, exe, matching_file))
{
TAGID tagName = SdbFindFirstTag(db, matching_file, TAG_NAME);
LPWSTR name = SdbGetStringTagPtr(db, tagName);
if (!wcscmp(name, L"*"))
{
// if attributes dont match main file, return FALSE!
continue;
}
snprintfW(buffer, _countof(buffer), fmt, dir, name);
if (!SdbpFileExists(buffer))
return FALSE;
}
return TRUE;
}
static void SdbpAddDatabaseGuid(PDB db, PSDBQUERYRESULT result)
{
size_t n;
for (n = 0; n < _countof(result->rgGuidDB); ++n)
{
if (!memcmp(&result->rgGuidDB[n], &db->database_id, sizeof(db->database_id)))
return;
if (result->dwCustomSDBMap & (1<<n))
continue;
memcpy(&result->rgGuidDB[n], &db->database_id, sizeof(result->rgGuidDB[n]));
result->dwCustomSDBMap |= (1<<n);
return;
}
}
static BOOL SdbpAddSingleLayerMatch(TAGREF layer, PSDBQUERYRESULT result)
{
size_t n;
for (n = 0; n < result->dwLayerCount; ++n)
{
if (result->atrLayers[n] == layer)
return FALSE;
}
if (n >= _countof(result->atrLayers))
return FALSE;
result->atrLayers[n] = layer;
result->dwLayerCount++;
return TRUE;
}
static BOOL SdbpAddNamedLayerMatch(HSDB hsdb, PCWSTR layerName, PSDBQUERYRESULT result)
{
TAGID database, layer;
TAGREF tr;
PDB db = hsdb->db;
database = SdbFindFirstTag(db, TAGID_ROOT, TAG_DATABASE);
if (database == TAGID_NULL)
return FALSE;
layer = SdbFindFirstNamedTag(db, database, TAG_LAYER, TAG_NAME, layerName);
if (layer == TAGID_NULL)
return FALSE;
if (!SdbTagIDToTagRef(hsdb, db, layer, &tr))
return FALSE;
if (!SdbpAddSingleLayerMatch(tr, result))
return FALSE;
SdbpAddDatabaseGuid(db, result);
return TRUE;
}
static void SdbpAddExeLayers(HSDB hsdb, PDB db, TAGID tagExe, PSDBQUERYRESULT result)
{
TAGID layer = SdbFindFirstTag(db, tagExe, TAG_LAYER);
while (layer != TAGID_NULL)
{
TAGREF tr;
TAGID layerIdTag = SdbFindFirstTag(db, layer, TAG_LAYER_TAGID);
DWORD tagId = SdbReadDWORDTag(db, layerIdTag, TAGID_NULL);
if (layerIdTag != TAGID_NULL &&
tagId != TAGID_NULL &&
SdbTagIDToTagRef(hsdb, db, tagId, &tr))
{
SdbpAddSingleLayerMatch(tr, result);
}
else
{
/* Try a name lookup */
TAGID layerTag = SdbFindFirstTag(db, layer, TAG_NAME);
if (layerTag != TAGID_NULL)
{
LPCWSTR layerName = SdbGetStringTagPtr(db, layerTag);
if (layerName)
{
SdbpAddNamedLayerMatch(hsdb, layerName, result);
}
}
}
layer = SdbFindNextTag(db, tagExe, layer);
}
}
static void SdbpAddExeMatch(HSDB hsdb, PDB db, TAGID tagExe, PSDBQUERYRESULT result)
{
size_t n;
TAGREF tr;
if (!SdbTagIDToTagRef(hsdb, db, tagExe, &tr))
return;
for (n = 0; n < result->dwExeCount; ++n)
{
if (result->atrExes[n] == tr)
return;
}
if (n >= _countof(result->atrExes))
return;
result->atrExes[n] = tr;
result->dwExeCount++;
SdbpAddExeLayers(hsdb, db, tagExe, result);
SdbpAddDatabaseGuid(db, result);
}
static ULONG SdbpAddLayerMatches(HSDB hsdb, PWSTR pwszLayers, DWORD pdwBytes, PSDBQUERYRESULT result)
{
PWSTR start = pwszLayers, p;
ULONG Added = 0;
const PWSTR end = pwszLayers + (pdwBytes / sizeof(WCHAR));
while (start < end && (*start == L'!' || *start == L'#' || *start == L' ' || *start == L'\t'))
start++;
if (start == end)
return 0;
do
{
while (*start == L' ' || *start == L'\t')
++start;
if (*start == UNICODE_NULL)
break;
p = wcspbrk(start, L" \t");
if (p)
*p = UNICODE_NULL;
if (SdbpAddNamedLayerMatch(hsdb, start, result))
Added++;
start = p + 1;
} while (start < end && p);
return Added;
}
static BOOL SdbpPropagateEnvLayers(HSDB hsdb, LPWSTR Environment, PSDBQUERYRESULT Result)
{
static const UNICODE_STRING EnvKey = RTL_CONSTANT_STRING(L"__COMPAT_LAYER");
UNICODE_STRING EnvValue;
NTSTATUS Status;
WCHAR Buffer[MAX_LAYER_LENGTH];
RtlInitEmptyUnicodeString(&EnvValue, Buffer, sizeof(Buffer));
Status = RtlQueryEnvironmentVariable_U(Environment, &EnvKey, &EnvValue);
if (!NT_SUCCESS(Status))
return FALSE;
return SdbpAddLayerMatches(hsdb, Buffer, EnvValue.Length, Result) > 0;
}
/**
* Opens specified shim database file Handle returned by this function may only be used by
@ -50,12 +252,12 @@ HSDB WINAPI SdbInitDatabase(DWORD flags, LPCWSTR path)
static const WCHAR drivers[] = {'\\','d','r','v','m','a','i','n','.','s','d','b',0};
LPCWSTR name;
WCHAR buffer[128];
HSDB sdb;
HSDB hsdb;
sdb = SdbAlloc(sizeof(SDB));
if (!sdb)
hsdb = SdbAlloc(sizeof(SDB));
if (!hsdb)
return NULL;
sdb->auto_loaded = 0;
hsdb->auto_loaded = 0;
/* Check for predefined databases */
if ((flags & HID_DATABASE_TYPE_MASK) && path == NULL)
@ -66,23 +268,24 @@ HSDB WINAPI SdbInitDatabase(DWORD flags, LPCWSTR path)
case SDB_DATABASE_MAIN_MSI: name = msi; break;
case SDB_DATABASE_MAIN_DRIVERS: name = drivers; break;
default:
SdbReleaseDatabase(sdb);
SdbReleaseDatabase(hsdb);
return NULL;
}
SdbGetAppPatchDir(NULL, buffer, 128);
memcpy(buffer + lstrlenW(buffer), name, SdbpStrlen(name));
memcpy(buffer + lstrlenW(buffer), name, SdbpStrsize(name));
flags = HID_DOS_PATHS;
}
sdb->db = SdbOpenDatabase(path ? path : buffer, (flags & 0xF) - 1);
hsdb->db = SdbOpenDatabase(path ? path : buffer, (flags & 0xF) - 1);
/* If database could not be loaded, a handle doesn't make sense either */
if (!sdb->db)
if (!hsdb->db)
{
SdbReleaseDatabase(sdb);
SdbReleaseDatabase(hsdb);
return NULL;
}
return sdb;
return hsdb;
}
/**
@ -103,7 +306,7 @@ void WINAPI SdbReleaseDatabase(HSDB hsdb)
* @param [in] hsdb Handle to the shim database.
* @param [in] path Path to executable for which we query database.
* @param [in] module_name Unused.
* @param [in] env Unused.
* @param [in] env The environment block to use
* @param [in] flags 0 or SDBGMEF_IGNORE_ENVIRONMENT.
* @param [out] result Pointer to structure in which query result shall be stored.
*
@ -112,14 +315,16 @@ void WINAPI SdbReleaseDatabase(HSDB hsdb)
BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
LPCWSTR env, DWORD flags, PSDBQUERYRESULT result)
{
static const WCHAR fmt[] = {'%','s','%','s',0};
BOOL ok, ret;
TAGID database, iter, attr;
BOOL ret = FALSE;
TAGID database, iter, name;
PATTRINFO attribs = NULL;
/*DWORD attr_count;*/
RTL_UNICODE_STRING_BUFFER DosApplicationName = { { 0 } };
WCHAR DosPathBuffer[MAX_PATH];
ULONG PathType = 0;
LPWSTR file_name;
WCHAR dir_path[128];
WCHAR buffer[256];
WCHAR wszLayers[MAX_LAYER_LENGTH];
DWORD dwSize;
PDB db;
/* Load default database if one is not specified */
@ -128,21 +333,49 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
/* To reproduce windows behaviour HID_DOS_PATHS needs
* to be specified when loading default database */
hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
if(hsdb)
if (hsdb)
hsdb->auto_loaded = TRUE;
}
ZeroMemory(result, sizeof(*result));
/* No database could be loaded */
if (!hsdb)
if (!hsdb || !path)
return FALSE;
/* We do not support multiple db's yet! */
db = hsdb->db;
/* Extract file name */
file_name = strrchrW(path, '\\') + 1;
RtlInitUnicodeString(&DosApplicationName.String, path);
RtlInitBuffer(&DosApplicationName.ByteBuffer, (PUCHAR)DosPathBuffer, sizeof(DosPathBuffer));
if (!NT_SUCCESS(RtlEnsureBufferSize(RTL_SKIP_BUFFER_COPY, &DosApplicationName.ByteBuffer, DosApplicationName.String.MaximumLength)))
{
SHIM_ERR("Failed to convert allocate buffer.");
goto Cleanup;
}
/* Update the internal buffer to contain the string */
memcpy(DosApplicationName.ByteBuffer.Buffer, path, DosApplicationName.String.MaximumLength);
/* Make sure the string uses our internal buffer (we want to modify the buffer,
and RtlNtPathNameToDosPathName does not always modify the String to point to the Buffer)! */
DosApplicationName.String.Buffer = (PWSTR)DosApplicationName.ByteBuffer.Buffer;
/* Extract directory path */
memcpy(dir_path, path, (size_t)(file_name - path) * sizeof(WCHAR));
if (!NT_SUCCESS(RtlNtPathNameToDosPathName(0, &DosApplicationName, &PathType, NULL)))
{
SHIM_ERR("Failed to convert %S to DOS Path.", path);
goto Cleanup;
}
/* Extract file name */
file_name = strrchrW(DosApplicationName.String.Buffer, '\\');
if (!file_name)
{
SHIM_ERR("Failed to find Exe name in %wZ.", &DosApplicationName.String);
goto Cleanup;
}
/* We will use the buffer for exe name and directory. */
*(file_name++) = UNICODE_NULL;
/* Get information about executable required to match it with database entry */
/*if (!SdbGetFileAttributes(path, &attribs, &attr_count))
@ -151,38 +384,28 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
/* DATABASE is list TAG which contains all executables */
database = SdbFindFirstTag(db, TAGID_ROOT, TAG_DATABASE);
if (database == TAGID_NULL)
return FALSE;
{
goto Cleanup;
}
/* EXE is list TAG which contains data required to match executable */
iter = SdbFindFirstTag(db, database, TAG_EXE);
/* Search for entry in database */
/* Search for entry in database, we should look into indexing tags! */
while (iter != TAGID_NULL)
{
LPWSTR foundName;
/* Check if exe name matches */
attr = SdbFindFirstTag(db, iter, TAG_NAME);
if (lstrcmpiW(SdbGetStringTagPtr(db, attr), file_name) == 0)
name = SdbFindFirstTag(db, iter, TAG_NAME);
/* If this is a malformed DB, (no TAG_NAME), we should not crash. */
foundName = SdbGetStringTagPtr(db, name);
if (foundName && !lstrcmpiW(foundName, file_name))
{
/* Assume that entry is found (in case there are no "matching files") */
ok = TRUE;
/* Check if all "matching files" exist */
/* TODO: check size/checksum as well */
for (attr = SdbFindFirstTag(db, attr, TAG_MATCHING_FILE);
attr != TAGID_NULL; attr = SdbFindNextTag(db, iter, attr))
/* We have a null terminator before the application name, so DosApplicationName only contains the path. */
if (SdbpMatchExe(db, iter, DosApplicationName.String.Buffer))
{
snprintfW(buffer, 256, fmt, dir_path, SdbGetStringTagPtr(db, attr));
if (!SdbpFileExists(buffer))
ok = FALSE;
}
/* Found it! */
if (ok)
{
/* TODO: fill result data */
/* TODO: there may be multiple matches */
ret = TRUE;
goto cleanup;
SdbpAddExeMatch(hsdb, db, iter, result);
}
}
@ -190,12 +413,31 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
iter = SdbFindNextTag(db, database, iter);
}
/* Exe not found */
ret = FALSE;
/* Restore the full path. */
*(--file_name) = L'\\';
cleanup:
SdbFreeFileAttributes(attribs);
if (hsdb->auto_loaded) SdbReleaseDatabase(hsdb);
dwSize = sizeof(wszLayers);
if (SdbGetPermLayerKeys(DosApplicationName.String.Buffer, wszLayers, &dwSize, GPLK_MACHINE | GPLK_USER))
{
SdbpAddLayerMatches(hsdb, wszLayers, dwSize, result);
ret = TRUE;
}
if (!(flags & SDBGMEF_IGNORE_ENVIRONMENT))
{
if (SdbpPropagateEnvLayers(hsdb, (LPWSTR)env, result))
{
ret = TRUE;
result->dwFlags |= SHIMREG_HAS_ENVIRONMENT;
}
}
Cleanup:
RtlFreeBuffer(&DosApplicationName.ByteBuffer);
if (attribs)
SdbFreeFileAttributes(attribs);
if (hsdb->auto_loaded)
SdbReleaseDatabase(hsdb);
return ret;
}