[APPHELP] Initial implementation of ApphelpCheckRunAppEx. CORE-10368
authorMark Jansen <mark.jansen@reactos.org>
Fri, 19 May 2017 20:13:08 +0000 (20:13 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Fri, 19 May 2017 20:13:08 +0000 (20:13 +0000)
svn path=/trunk/; revision=74601

reactos/dll/appcompat/apphelp/apphelp.c
reactos/dll/appcompat/apphelp/apphelp.h
reactos/dll/appcompat/apphelp/apphelp.spec
reactos/dll/appcompat/apphelp/hsdb.c

index d5c5016..90bc9fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2011 André Hentschel
  * Copyright 2013 Mislav Blažević
 /*
  * 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
  *
  * 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 "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
 
 /* from dpfilter.h */
 #define DPFLTR_APPCOMPAT_ID 123
 #endif
 
 ULONG g_ShimDebugLevel = 0xffffffff;
 #endif
 
 ULONG g_ShimDebugLevel = 0xffffffff;
+HMODULE g_hInstance;
 
 void ApphelppInitDebugLevel(void)
 {
 
 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];
 
     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);
     Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
-    RtlReleasePebLock();
 
     if (NT_SUCCESS(Status))
     {
 
     if (NT_SUCCESS(Status))
     {
@@ -61,6 +58,7 @@ void ApphelppInitDebugLevel(void)
     g_ShimDebugLevel = NewLevel;
 }
 
     g_ShimDebugLevel = NewLevel;
 }
 
+
 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
 {
     switch (reason)
 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:
             return FALSE;    /* prefer native version */
 #endif
         case DLL_PROCESS_ATTACH:
+            g_hInstance = hinst;
             DisableThreadLibraryCalls( hinst );
             SdbpHeapInit();
             break;
             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);
         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);
     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
 #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
 }
 
 #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;
+}
+
+
index fd7cbc5..2e1c4f4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2013 Mislav Blažević
 /*
  * 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
  *
  * 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)
 
 #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 {
 #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);
 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);
 
 /* 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 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);
 
 
 BOOL WINAPI SdbTagIDToTagRef(HSDB hsdb, PDB pdb, TAGID tiWhich, TAGREF* ptrWhich);
 
 
index dfebf83..0eecfbf 100644 (file)
@@ -3,7 +3,7 @@
 @ stdcall ApphelpCheckInstallShieldPackage(ptr wstr)
 @ stub ApphelpCheckMsiPackage
 @ stub ApphelpCheckRunApp
 @ 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
 @ stdcall ApphelpCheckShellObject(ptr long ptr)
 @ stub ApphelpCreateAppcompatData
 @ stub ApphelpFixMsiPackage
index 805ac5c..bed1361 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2011 André Hentschel
  * Copyright 2013 Mislav Blažević
 /*
  * 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
  *
  * 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"
 
 
 #include "wine/unicode.h"
 
+#define MAX_LAYER_LENGTH            256
+#define GPLK_USER                   1
+#define GPLK_MACHINE                2
 
 static BOOL WINAPI SdbpFileExists(LPCWSTR path)
 {
 
 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));
 }
 
     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
 
 /**
  * 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];
     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;
         return NULL;
-    sdb->auto_loaded = 0;
+    hsdb->auto_loaded = 0;
 
     /* Check for predefined databases */
     if ((flags & HID_DATABASE_TYPE_MASK) && path == NULL)
 
     /* 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:
             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);
                 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 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 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]  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.
  *
  * @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)
 {
 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;*/
     PATTRINFO attribs = NULL;
     /*DWORD attr_count;*/
+    RTL_UNICODE_STRING_BUFFER DosApplicationName = { { 0 } };
+    WCHAR DosPathBuffer[MAX_PATH];
+    ULONG PathType = 0;
     LPWSTR file_name;
     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 */
     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);
         /* 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;
     }
 
             hsdb->auto_loaded = TRUE;
     }
 
+    ZeroMemory(result, sizeof(*result));
+
     /* No database could be loaded */
     /* No database could be loaded */
-    if (!hsdb)
+    if (!hsdb || !path)
         return FALSE;
 
         return FALSE;
 
+    /* We do not support multiple db's yet! */
     db = hsdb->db;
 
     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 */
     /* Extract file name */
-    file_name = strrchrW(path, '\\') + 1;
+    file_name = strrchrW(DosApplicationName.String.Buffer, '\\');
+    if (!file_name)
+    {
+        SHIM_ERR("Failed to find Exe name in %wZ.", &DosApplicationName.String);
+        goto Cleanup;
+    }
 
 
-    /* Extract directory path */
-    memcpy(dir_path, path, (size_t)(file_name - path) * sizeof(WCHAR));
+    /* 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))
 
     /* 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)
     /* 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);
 
 
     /* 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)
     {
     while (iter != TAGID_NULL)
     {
+        LPWSTR foundName;
         /* Check if exe name matches */
         /* 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;
                 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);
     }
 
         iter = SdbFindNextTag(db, database, iter);
     }
 
-    /* Exe not found */
-    ret = FALSE;
+    /* 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:
-    SdbFreeFileAttributes(attribs);
-    if (hsdb->auto_loaded) SdbReleaseDatabase(hsdb);
+Cleanup:
+    RtlFreeBuffer(&DosApplicationName.ByteBuffer);
+    if (attribs)
+        SdbFreeFileAttributes(attribs);
+    if (hsdb->auto_loaded)
+        SdbReleaseDatabase(hsdb);
     return ret;
 }
 
     return ret;
 }