Author: mjansen Date: Fri May 19 20:13:08 2017 New Revision: 74601 URL: http://svn.reactos.org/svn/reactos?rev=74601&view=rev Log: [APPHELP] Initial implementation of ApphelpCheckRunAppEx. CORE-10368
Modified: trunk/reactos/dll/appcompat/apphelp/apphelp.c trunk/reactos/dll/appcompat/apphelp/apphelp.h trunk/reactos/dll/appcompat/apphelp/apphelp.spec trunk/reactos/dll/appcompat/apphelp/hsdb.c Modified: trunk/reactos/dll/appcompat/apphelp/apphelp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/apphelp.c?rev=74601&r1=74600&r2=74601&view=diff ============================================================================== --- trunk/reactos/dll/appcompat/apphelp/apphelp.c [iso-8859-1] (original) +++ trunk/reactos/dll/appcompat/apphelp/apphelp.c [iso-8859-1] Fri May 19 20:13:08 2017 @@ -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 "wine/winternl.h" +#include "ndk/rtlfuncs.h" +#include "ndk/kdtypes.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; - - /* Hold the lock as short as possible. */ - RtlAcquirePebLock(); + RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer)); + Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue); - RtlReleasePebLock(); if (NT_SUCCESS(Status)) { @@ -60,6 +57,7 @@ } g_ShimDebugLevel = NewLevel; } + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { @@ -70,6 +68,7 @@ return FALSE; /* prefer native version */ #endif case DLL_PROCESS_ATTACH: + g_hInstance = hinst; DisableThreadLibraryCalls( hinst ); SdbpHeapInit(); break; @@ -145,9 +144,11 @@ 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 @@ #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; +} + + Modified: trunk/reactos/dll/appcompat/apphelp/apphelp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/apphelp.h?rev=74601&r1=74600&r2=74601&view=diff ============================================================================== --- trunk/reactos/dll/appcompat/apphelp/apphelp.h [iso-8859-1] (original) +++ trunk/reactos/dll/appcompat/apphelp/apphelp.h [iso-8859-1] Fri May 19 20:13:08 2017 @@ -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 @@ #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 @@ 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 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); Modified: trunk/reactos/dll/appcompat/apphelp/apphelp.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/apphelp.spec?rev=74601&r1=74600&r2=74601&view=diff ============================================================================== --- trunk/reactos/dll/appcompat/apphelp/apphelp.spec [iso-8859-1] (original) +++ trunk/reactos/dll/appcompat/apphelp/apphelp.spec [iso-8859-1] Fri May 19 20:13:08 2017 @@ -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 Modified: trunk/reactos/dll/appcompat/apphelp/hsdb.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/appcompat/apphelp/hsdb.c?rev=74601&r1=74600&r2=74601&view=diff ============================================================================== --- trunk/reactos/dll/appcompat/apphelp/hsdb.c [iso-8859-1] (original) +++ trunk/reactos/dll/appcompat/apphelp/hsdb.c [iso-8859-1] Fri May 19 20:13:08 2017 @@ -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,12 +26,214 @@ #include "wine/unicode.h" +#define MAX_LAYER_LENGTH 256 +#define GPLK_USER 1 +#define GPLK_MACHINE 2 static BOOL WINAPI SdbpFileExists(LPCWSTR path) { DWORD attr = GetFileAttributesW(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; +} + /** @@ -50,12 +252,12 @@ static const WCHAR drivers[] = {'\\','d','r','v','m','a','i','n','.','s','d','b',0}; LPCWSTR name; WCHAR buffer[128]; - HSDB sdb; - - sdb = SdbAlloc(sizeof(SDB)); - if (!sdb) + HSDB hsdb; + + 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 @@ 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)); - } - - sdb->db = SdbOpenDatabase(path ? path : buffer, (flags & 0xF) - 1); + memcpy(buffer + lstrlenW(buffer), name, SdbpStrsize(name)); + flags = HID_DOS_PATHS; + } + + 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) - { - SdbReleaseDatabase(sdb); + if (!hsdb->db) + { + SdbReleaseDatabase(hsdb); return NULL; } - return sdb; + return hsdb; } /** @@ -103,7 +306,7 @@ * @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 @@ 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 @@ /* 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) - return FALSE; - + if (!hsdb || !path) + return FALSE; + + /* We do not support multiple db's yet! */ db = hsdb->db; + 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; + + 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(path, '\\') + 1; - - /* Extract directory path */ - memcpy(dir_path, path, (size_t)(file_name - path) * sizeof(WCHAR)); + 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 @@ /* 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) - { - /* 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)) + 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)) + { + /* 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 @@ iter = SdbFindNextTag(db, database, iter); } - /* Exe not found */ - ret = FALSE; - -cleanup: - SdbFreeFileAttributes(attribs); - if (hsdb->auto_loaded) SdbReleaseDatabase(hsdb); + /* Restore the full path. */ + *(--file_name) = L'\\'; + + 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; }