[APPHELP]
authorThomas Faber <thomas.faber@reactos.org>
Thu, 31 Mar 2016 12:54:05 +0000 (12:54 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Thu, 31 Mar 2016 12:54:05 +0000 (12:54 +0000)
- Add apphelp.dll. Patch by Mark Jansen, partially based on work by Mislav Blažević and the Wine team.
CORE-10367 #resolve

svn path=/trunk/; revision=71084

reactos/dll/CMakeLists.txt
reactos/dll/appcompat/CMakeLists.txt [new file with mode: 0644]
reactos/dll/appcompat/apphelp/CMakeLists.txt [new file with mode: 0644]
reactos/dll/appcompat/apphelp/apphelp.c [new file with mode: 0644]
reactos/dll/appcompat/apphelp/apphelp.h [new file with mode: 0644]
reactos/dll/appcompat/apphelp/apphelp.spec [new file with mode: 0644]
reactos/dll/appcompat/apphelp/layer.c [new file with mode: 0644]
reactos/dll/appcompat/apphelp/sdbapi.c [new file with mode: 0644]

index fe133d7..3037cc6 100644 (file)
@@ -1,5 +1,6 @@
 
 add_subdirectory(3rdparty)
+add_subdirectory(appcompat)
 add_subdirectory(cpl)
 add_subdirectory(directx)
 add_subdirectory(keyboard)
diff --git a/reactos/dll/appcompat/CMakeLists.txt b/reactos/dll/appcompat/CMakeLists.txt
new file mode 100644 (file)
index 0000000..34632ff
--- /dev/null
@@ -0,0 +1,2 @@
+
+add_subdirectory(apphelp)
diff --git a/reactos/dll/appcompat/apphelp/CMakeLists.txt b/reactos/dll/appcompat/apphelp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e1beb19
--- /dev/null
@@ -0,0 +1,20 @@
+
+spec2def(apphelp.dll apphelp.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+    apphelp.c
+    sdbapi.c
+    layer.c
+    apphelp.spec
+    apphelp.h
+    ${CMAKE_CURRENT_BINARY_DIR}/apphelp_stubs.c)
+
+add_library(apphelp SHARED
+    ${SOURCE}
+    ${CMAKE_CURRENT_BINARY_DIR}/apphelp.def)
+
+set_module_type(apphelp win32dll)
+target_link_libraries(apphelp wine)
+#add_delay_importlibs(apphelp version imagehlp user32)
+add_importlibs(apphelp msvcrt kernel32 ntdll)
+add_cd_file(TARGET apphelp DESTINATION reactos/system32 FOR all)
diff --git a/reactos/dll/appcompat/apphelp/apphelp.c b/reactos/dll/appcompat/apphelp/apphelp.c
new file mode 100644 (file)
index 0000000..7a888af
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 André Hentschel
+ * Copyright 2013 Mislav Blažević
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winver.h"
+#include "strsafe.h"
+#include "apphelp.h"
+
+#include "wine/winternl.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+/* from dpfilter.h */
+#define DPFLTR_APPCOMPAT_ID 123
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(StatCode)  ((NTSTATUS)(StatCode) >= 0)
+#endif
+
+ULONG g_ShimDebugLevel = 0xffffffff;
+
+void ApphelppInitDebugLevel(void)
+{
+    UNICODE_STRING DebugKey, DebugValue;
+    NTSTATUS Status;
+    ULONG NewLevel = 0;
+    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();
+    Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
+    RtlReleasePebLock();
+
+    if (NT_SUCCESS(Status))
+    {
+        if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
+            NewLevel = 0;
+    }
+    g_ShimDebugLevel = NewLevel;
+}
+
+BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
+{
+    switch (reason)
+    {
+#ifndef __REACTOS__
+        case DLL_WINE_PREATTACH:
+            return FALSE;    /* prefer native version */
+#endif
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls( hinst );
+            SdbpHeapInit();
+            break;
+        case DLL_PROCESS_DETACH:
+            SdbpHeapDeinit();
+            break;
+    }
+    return TRUE;
+}
+
+
+/**
+ * Outputs diagnostic info.
+ *
+ * @param [in]  Level           The level to log this message with, choose any of [SHIM_ERR,
+ *                              SHIM_WARN, SHIM_INFO].
+ * @param [in]  FunctionName    The function this log should be attributed to.
+ * @param [in]  Format          The format string.
+ * @param   ...                 Variable arguments providing additional information.
+ *
+ * @return  Success: TRUE Failure: FALSE.
+ */
+BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...)
+{
+    char Buffer[512];
+    va_list ArgList;
+    char* Current = Buffer, *LevelStr;
+    size_t Length = sizeof(Buffer);
+
+    if (g_ShimDebugLevel == 0xffffffff)
+        ApphelppInitDebugLevel();
+
+    if (Level > g_ShimDebugLevel)
+        return FALSE;
+
+    switch (Level)
+    {
+    case SHIM_ERR:
+        LevelStr = "Err ";
+        Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL);
+        break;
+    case SHIM_WARN:
+        LevelStr = "Warn";
+        Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL);
+        break;
+    case SHIM_INFO:
+        LevelStr = "Info";
+        Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
+        break;
+    default:
+        LevelStr = "User";
+        Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
+        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);
+    return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
+}
+
diff --git a/reactos/dll/appcompat/apphelp/apphelp.h b/reactos/dll/appcompat/apphelp/apphelp.h
new file mode 100644 (file)
index 0000000..8bed7b6
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Mislav Blažević
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef APPHELP_H
+#define APPHELP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum _SHIM_LOG_LEVEL {
+    SHIM_ERR = 1,
+    SHIM_WARN = 2,
+    SHIM_INFO = 3,
+}SHIM_LOG_LEVEL;
+
+/* apphelp.c */
+BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...);
+extern ULONG g_ShimDebugLevel;
+
+#define SHIM_ERR(fmt, ...)  do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_ERR, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
+#define SHIM_WARN(fmt, ...)  do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_WARN, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
+#define SHIM_INFO(fmt, ...)  do { if (g_ShimDebugLevel) ShimDbgPrint(SHIM_INFO, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while (0)
+
+
+/* sdbapi.c */
+void SdbpHeapInit(void);
+void SdbpHeapDeinit(void);
+#if SDBAPI_DEBUG_ALLOC
+
+LPVOID SdbpAlloc(SIZE_T size, int line, const char* file);
+LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size, int line, const char* file);
+void SdbpFree(LPVOID mem, int line, const char* file);
+
+#define SdbAlloc(size) SdbpAlloc(size, __LINE__, __FILE__)
+#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size, __LINE__, __FILE__)
+#define SdbFree(mem) SdbpFree(mem, __LINE__, __FILE__)
+
+#else
+
+LPVOID SdbpAlloc(SIZE_T size);
+LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size);
+void SdbpFree(LPVOID mem);
+
+#define SdbAlloc(size) SdbpAlloc(size)
+#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size)
+#define SdbFree(mem) SdbpFree(mem)
+
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // APPHELP_H
diff --git a/reactos/dll/appcompat/apphelp/apphelp.spec b/reactos/dll/appcompat/apphelp/apphelp.spec
new file mode 100644 (file)
index 0000000..61f3302
--- /dev/null
@@ -0,0 +1,175 @@
+@ stdcall AllowPermLayer(wstr)
+@ stub ApphelpCheckExe
+@ stub ApphelpCheckInstallShieldPackage
+@ stub ApphelpCheckMsiPackage
+@ stub ApphelpCheckRunApp
+@ stub ApphelpCheckRunAppEx
+@ stub ApphelpCheckShellObject
+@ stub ApphelpCreateAppcompatData
+@ stub ApphelpFixMsiPackage
+@ stub ApphelpFixMsiPackageExe
+@ stub ApphelpFreeFileAttributes
+@ stub ApphelpGetFileAttributes
+@ stub ApphelpGetMsiProperties
+@ stub ApphelpGetNTVDMInfo
+@ stub ApphelpParseModuleData
+@ stub ApphelpQueryModuleData
+@ stub ApphelpQueryModuleDataEx
+@ stub ApphelpUpdateCacheEntry
+@ stub GetPermLayers
+@ stub SdbAddLayerTagRefToQuery
+@ stub SdbApphelpNotify
+@ stub SdbApphelpNotifyExSdbApphelpNotifyEx
+@ stub SdbBeginWriteListTag
+@ stub SdbBuildCompatEnvVariables
+@ stub SdbCloseApphelpInformation
+@ stub SdbCloseDatabase
+@ stub SdbCloseDatabaseWrite
+@ stub SdbCloseLocalDatabase
+@ stub SdbCommitIndexes
+@ stub SdbCreateDatabase
+@ stub SdbCreateHelpCenterURL
+@ stub SdbCreateMsiTransformFile
+@ stub SdbDeclareIndex
+@ stub SdbDumpSearchPathPartCaches
+@ stub SdbEnumMsiTransforms
+@ stub SdbEndWriteListTag
+@ stub SdbEscapeApphelpURL
+@ stub SdbFindFirstDWORDIndexedTag
+@ stub SdbFindFirstMsiPackage
+@ stub SdbFindFirstMsiPackage_Str
+@ stub SdbFindFirstNamedTag
+@ stub SdbFindFirstStringIndexedTag
+@ stub SdbFindFirstTag
+@ stub SdbFindFirstTagRef
+@ stub SdbFindNextDWORDIndexedTag
+@ stub SdbFindNextMsiPackage
+@ stub SdbFindNextStringIndexedTag
+@ stub SdbFindNextTag
+@ stub SdbFindNextTagRef
+@ stub SdbFreeDatabaseInformation
+@ stub SdbFreeFileAttributes
+@ stub SdbFreeFileInfo
+@ stub SdbFreeFlagInfo
+@ stub SdbGetAppCompatDataSize
+@ stub SdbGetAppPatchDir
+@ stub SdbGetBinaryTagData
+@ stub SdbGetDatabaseID
+@ stub SdbGetDatabaseInformation
+@ stub SdbGetDatabaseInformationByName
+@ stub SdbGetDatabaseMatch
+@ stub SdbGetDatabaseVersion
+@ stub SdbGetDllPath
+@ stub SdbGetEntryFlags
+@ stub SdbGetFileAttributes
+@ stub SdbGetFileImageType
+@ stub SdbGetFileImageTypeEx
+@ stub SdbGetFileInfo
+@ stub SdbGetFirstChild
+@ stub SdbGetIndex
+@ stub SdbGetItemFromItemRef
+@ stub SdbGetLayerName
+@ stub SdbGetLayerTagRef
+@ stub SdbGetLocalPDB
+@ stub SdbGetMatchingExe
+@ stub SdbGetMsiPackageInformation
+@ stub SdbGetNamedLayer
+@ stub SdbGetNextChild
+@ stub SdbGetNthUserSdb
+@ stdcall SdbGetPermLayerKeys(wstr wstr ptr long)
+@ stub SdbGetShowDebugInfoOption
+@ stub SdbGetShowDebugInfoOptionValue
+@ stub SdbGetStandardDatabaseGUID
+@ stub SdbGetStringTagPtr
+@ stub SdbGetTagDataSize
+@ stub SdbGetTagFromTagID
+@ stub SdbGrabMatchingInfo
+@ stub SdbGrabMatchingInfoEx
+@ stub SdbGUIDFromString
+@ stub SdbGUIDToString
+@ stub SdbInitDatabase
+@ stub SdbInitDatabaseEx
+@ stub SdbIsNullGUID
+@ stub SdbIsStandardDatabase
+@ stub SdbIsTagrefFromLocalDB
+@ stub SdbIsTagrefFromMainDB
+@ stub SdbLoadString
+@ stub SdbMakeIndexKeyFromString
+@ stub SdbOpenApphelpDetailsDatabase
+@ stub SdbOpenApphelpDetailsDatabaseSP
+@ stub SdbOpenApphelpInformation
+@ stub SdbOpenApphelpInformationByID
+@ stub SdbOpenApphelpResourceFile
+@ stub SdbOpenDatabase
+@ stub SdbOpenDbFromGuid
+@ stub SdbOpenLocalDatabase
+@ stub SdbPackAppCompatData
+@ stub SdbQueryApphelpInformation
+@ stub SdbQueryBlockUpgrade
+@ stub SdbQueryContext
+@ stub SdbQueryData
+@ stub SdbQueryDataEx
+@ stub SdbQueryDataExTagID
+@ stub SdbQueryFlagInfo
+@ stub SdbQueryName
+@ stub SdbQueryReinstallUpgrade
+@ stub SdbReadApphelpData
+@ stub SdbReadApphelpDetailsData
+@ stub SdbReadBinaryTag
+@ stub SdbReadBYTETag
+@ stub SdbReadDWORDTag
+@ stub SdbReadDWORDTagRef
+@ stub SdbReadEntryInformation
+@ stub SdbReadMsiTransformInfo
+@ stub SdbReadPatchBits
+@ stub SdbReadQWORDTag
+@ stub SdbReadQWORDTagRef
+@ stub SdbReadStringTag
+@ stub SdbReadStringTagRef
+@ stub SdbReadWORDTag
+@ stub SdbReadWORDTagRef
+@ stub SdbRegisterDatabase
+@ stub SdbReleaseDatabase
+@ stub SdbReleaseMatchingExe
+@ stub SdbResolveDatabase
+@ stub SdbSetApphelpDebugParameters
+@ stub SdbSetEntryFlags
+@ stub SdbSetImageType
+@ stdcall SdbSetPermLayerKeys(wstr wstr long)
+@ stub SdbShowApphelpDialog
+@ stub SdbShowApphelpFromQuery
+@ stub SdbStartIndexing
+@ stub SdbStopIndexing
+@ stub SdbStringDuplicate
+@ stub SdbStringReplace
+@ stub SdbStringReplaceArray
+@ stub SdbTagIDToTagRef
+@ stub SdbTagRefToTagID
+@ stub SdbTagToString
+@ stub SdbUnregisterDatabase
+@ stub SdbWriteBinaryTag
+@ stub SdbWriteBinaryTagFromFile
+@ stub SdbWriteBYTETag
+@ stub SdbWriteDWORDTag
+@ stub SdbWriteNULLTag
+@ stub SdbWriteQWORDTag
+@ stub SdbWriteStringRefTag
+@ stub SdbWriteStringTag
+@ stub SdbWriteStringTagDirect
+@ stub SdbWriteWORDTag
+@ stub SE_DllLoaded
+@ stub SE_DllUnloaded
+@ stub SE_GetHookAPIs
+@ stub SE_GetMaxShimCount
+@ stub SE_GetProcAddressLoad
+@ stub SE_GetShimCount
+@ stub SE_InstallAfterInit
+@ stub SE_InstallBeforeInit
+@ stub SE_IsShimDll
+@ stub SE_LdrEntryRemoved
+@ stub SE_ProcessDying
+@ stub SetPermLayers
+@ cdecl ShimDbgPrint(long str str)
+@ stub ShimDumpCache
+@ stub ShimFlushCache
+@ stdcall SetPermLayerState(wstr wstr long long long)
diff --git a/reactos/dll/appcompat/apphelp/layer.c b/reactos/dll/appcompat/apphelp/layer.c
new file mode 100644 (file)
index 0000000..b44555d
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "strsafe.h"
+#include <ntndk.h>
+#include "apphelp.h"
+
+#define GPLK_USER                   1
+#define GPLK_MACHINE                2
+#define MAX_LAYER_LENGTH            256
+#define LAYER_APPLY_TO_SYSTEM_EXES  1
+#define LAYER_UNK_FLAG2             2
+
+#ifndef REG_SZ
+#define REG_SZ                      1
+#endif
+
+#if defined(__GNUC__)
+#define APPCOMPAT_LAYER_KEY     (const WCHAR[]){'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p','C','o','m','p','a','t','F','l','a','g','s','\\','L','a','y','e','r','s',0}
+#define REGISTRY_MACHINE        (const WCHAR[]){'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',0}
+#define SPACE_ONLY              (const WCHAR[]){' ',0}
+#define DISALLOWED_LAYER_CHARS  (const WCHAR[]){' ','#','!',0}
+#define LAYER_SEPARATORS        (const WCHAR[]){' ','\t',0}
+#define SIGN_MEDIA_FMT          (const WCHAR[]){'S','I','G','N','.','M','E','D','I','A','=','%','X',' ','%','s',0}
+
+#else
+#define APPCOMPAT_LAYER_KEY     L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"
+#define REGISTRY_MACHINE        L"\\Registry\\Machine"
+#define SPACE_ONLY              L" "
+#define DISALLOWED_LAYER_CHARS  L" #!"
+#define LAYER_SEPARATORS        L" \t"
+#define SIGN_MEDIA_FMT          L"SIGN.MEDIA=%X %s"
+#endif
+
+
+typedef struct SDB_TMP_STR
+{
+    UNICODE_STRING Str;
+    WCHAR FixedBuffer[MAX_PATH];
+} SDB_TMP_STR, *PSDB_TMP_STR;
+
+void SdbpInitTempStr(PSDB_TMP_STR String)
+{
+    String->Str.Buffer = String->FixedBuffer;
+    String->Str.Length = 0;
+    String->Str.MaximumLength = sizeof(String->FixedBuffer);
+}
+
+void SdbpFreeTempStr(PSDB_TMP_STR String)
+{
+    if (String->Str.Buffer != String->FixedBuffer)
+    {
+        SdbFree(String->Str.Buffer);
+    }
+}
+
+void SdbpResizeTempStr(PSDB_TMP_STR String, WORD newLength)
+{
+    if (newLength > String->Str.MaximumLength)
+    {
+        SdbpFreeTempStr(String);
+        String->Str.MaximumLength = newLength * sizeof(WCHAR);
+        String->Str.Buffer = SdbAlloc(String->Str.MaximumLength);
+        String->Str.Length = 0;
+    }
+}
+
+BOOL SdbpGetLongPathName(PCWSTR wszPath, PSDB_TMP_STR Result)
+{
+    DWORD max = Result->Str.MaximumLength / 2;
+    DWORD ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max);
+    if (ret)
+    {
+        if (ret >= max)
+        {
+            SdbpResizeTempStr(Result, ret);
+            max = Result->Str.MaximumLength / 2;
+            ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max);
+        }
+        if (ret && ret < max)
+        {
+            Result->Str.Length = ret * 2;
+            return TRUE;
+        }
+    }
+    SHIM_ERR("Failed to convert short path to long path error 0x%lx\n", GetLastError());
+    return FALSE;
+}
+
+BOOL SdbpIsPathOnRemovableMedia(PCWSTR Path)
+{
+    WCHAR tmp[] = { 'A',':','\\',0 };
+    ULONG type;
+    if (!Path)
+    {
+        SHIM_ERR("Invalid argument\n");
+        return FALSE;
+    }
+    switch (Path[1])
+    {
+    case L':':
+        break;
+    case L'\\':
+        SHIM_INFO("\"%S\" is a network path.\n", Path);
+        return FALSE;
+    default:
+        SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path);
+        return FALSE;
+    }
+    tmp[0] = Path[0];
+    type = GetDriveTypeW(tmp);
+
+    return type == DRIVE_REMOVABLE || type == DRIVE_CDROM;
+}
+
+BOOL SdbpBuildSignMediaId(PSDB_TMP_STR LongPath)
+{
+    SDB_TMP_STR Scratch;
+    PWCHAR Ptr;
+
+    SdbpInitTempStr(&Scratch);
+    SdbpResizeTempStr(&Scratch, LongPath->Str.Length / sizeof(WCHAR) + 30);
+    StringCbCopyNW(Scratch.Str.Buffer, Scratch.Str.MaximumLength, LongPath->Str.Buffer, LongPath->Str.Length);
+    Ptr = wcsrchr(LongPath->Str.Buffer, '\\');
+    if (Ptr)
+    {
+        HANDLE FindHandle;
+        WIN32_FIND_DATAW FindData;
+        Ptr[1] = '*';
+        Ptr[2] = '\0';
+        FindHandle = FindFirstFileW(LongPath->Str.Buffer, &FindData);
+        if (FindHandle != INVALID_HANDLE_VALUE)
+        {
+            DWORD SignMedia = 0;
+            do
+            {
+                if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && FindData.nFileSizeLow)
+                    SignMedia = SignMedia << 1 ^ FindData.nFileSizeLow;
+            } while (FindNextFileW(FindHandle, &FindData));
+
+            FindClose(FindHandle);
+            SdbpResizeTempStr(LongPath, (LongPath->Str.Length >> 1) + 20);
+            StringCbPrintfW(LongPath->Str.Buffer, LongPath->Str.MaximumLength, SIGN_MEDIA_FMT, SignMedia, Scratch.Str.Buffer + 3);
+            LongPath->Str.Length = wcslen(LongPath->Str.Buffer) * sizeof(WCHAR);
+            SdbpFreeTempStr(&Scratch);
+            return TRUE;
+        }
+    }
+    SdbpFreeTempStr(&Scratch);
+    SdbpFreeTempStr(LongPath);
+    return FALSE;
+}
+
+BOOL SdbpResolvePath(PSDB_TMP_STR LongPath, PCWSTR wszPath)
+{
+    SdbpInitTempStr(LongPath);
+    if (!SdbpGetLongPathName(wszPath, LongPath))
+    {
+        SdbpFreeTempStr(LongPath);
+        return FALSE;
+    }
+    if (SdbpIsPathOnRemovableMedia(LongPath->Str.Buffer))
+    {
+        return SdbpBuildSignMediaId(LongPath);
+    }
+    return TRUE;
+}
+
+static ACCESS_MASK g_QueryFlag = 0xffffffff;
+ACCESS_MASK QueryFlag(void)
+{
+    if (g_QueryFlag == 0xffffffff)
+    {
+        ULONG_PTR wow64_ptr = 0;
+        NTSTATUS Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64_ptr, sizeof(wow64_ptr), NULL);
+        g_QueryFlag = (NT_SUCCESS(Status) && wow64_ptr != 0) ? KEY_WOW64_64KEY : 0;
+    }
+    return g_QueryFlag;
+}
+
+NTSTATUS SdbpOpenKey(PUNICODE_STRING FullPath, BOOL bMachine, ACCESS_MASK Access, PHANDLE KeyHandle)
+{
+    UNICODE_STRING BasePath;
+    const WCHAR* LayersKey = APPCOMPAT_LAYER_KEY;
+    OBJECT_ATTRIBUTES ObjectLayer = RTL_INIT_OBJECT_ATTRIBUTES(FullPath, OBJ_CASE_INSENSITIVE);
+    NTSTATUS Status;
+    FullPath->Buffer = NULL;
+    FullPath->Length = FullPath->MaximumLength = 0;
+    if (bMachine)
+    {
+        RtlInitUnicodeString(&BasePath, REGISTRY_MACHINE);
+    }
+    else
+    {
+        Status = RtlFormatCurrentUserKeyPath(&BasePath);
+        if (!NT_SUCCESS(Status))
+        {
+            SHIM_ERR("Unable to aquire user registry key, Error: 0x%lx\n", Status);
+            return Status;
+        }
+    }
+    FullPath->MaximumLength = BasePath.Length + (wcslen(LayersKey) + 1) * sizeof(WCHAR);
+    FullPath->Buffer = SdbAlloc(FullPath->MaximumLength);
+    FullPath->Length = 0;
+    RtlAppendUnicodeStringToString(FullPath, &BasePath);
+    if (!bMachine)
+        RtlFreeUnicodeString(&BasePath);
+    RtlAppendUnicodeToString(FullPath, LayersKey);
+
+    Status = NtOpenKey(KeyHandle, Access | QueryFlag(), &ObjectLayer);
+    if (!NT_SUCCESS(Status))
+    {
+        SHIM_ERR("Unable to open Key  \"%wZ\" Status 0x%lx\n", FullPath, Status);
+        SdbFree(FullPath->Buffer);
+        FullPath->Buffer = NULL;
+    }
+    return Status;
+}
+
+
+BOOL SdbpGetPermLayersInternal(PUNICODE_STRING FullPath, PWSTR pwszLayers, PDWORD pdwBytes, BOOL bMachine)
+{
+    UNICODE_STRING FullKey;
+    ULONG ValueBuffer[(MAX_LAYER_LENGTH * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1) / sizeof(ULONG)];
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
+    ULONG Length = 0;
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+
+    Status = SdbpOpenKey(&FullKey, bMachine, KEY_QUERY_VALUE, &KeyHandle);
+    if (NT_SUCCESS(Status))
+    {
+        Status = NtQueryValueKey(KeyHandle, FullPath, KeyValuePartialInformation, PartialInfo, sizeof(ValueBuffer), &Length);
+        if (NT_SUCCESS(Status))
+        {
+            StringCbCopyNW(pwszLayers, *pdwBytes, (PCWSTR)PartialInfo->Data, PartialInfo->DataLength);
+            *pdwBytes = PartialInfo->DataLength;
+        }
+        else
+        {
+            SHIM_INFO("Failed to read value info from Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
+        }
+        NtClose(KeyHandle);
+        SdbFree(FullKey.Buffer);
+    }
+    return NT_SUCCESS(Status);
+}
+
+BOOL SdbDeletePermLayerKeys(PCWSTR wszPath, BOOL bMachine)
+{
+    UNICODE_STRING FullKey;
+    SDB_TMP_STR LongPath;
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+
+    if (!SdbpResolvePath(&LongPath, wszPath))
+        return FALSE;
+
+    Status = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle);
+    if (NT_SUCCESS(Status))
+    {
+        Status = NtDeleteValueKey(KeyHandle, &LongPath.Str);
+        if (!NT_SUCCESS(Status))
+        {
+            SHIM_INFO("Failed to delete value from Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
+            /* This is what we want, so if the key didnt exist, we should not fail :) */
+            if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+                Status = STATUS_SUCCESS;
+        }
+        NtClose(KeyHandle);
+        SdbFree(FullKey.Buffer);
+    }
+    SdbpFreeTempStr(&LongPath);
+    return NT_SUCCESS(Status);
+}
+
+BOOL SdbpMatchLayer(PCWSTR start, PCWSTR end, PCWSTR compare)
+{
+    size_t len;
+    if (!end)
+        return !wcsicmp(start, compare);
+    len = end - start;
+    return wcslen(compare) == len && !_wcsnicmp(start, compare, len);
+}
+
+BOOL SdbpAppendLayer(PWSTR target, DWORD len, PCWSTR layer, PCWSTR end)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    if (target[0])
+        Status = StringCbCatW(target, len, SPACE_ONLY);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (end)
+            Status = StringCbCatNW(target, len, layer, (end - layer) * sizeof(WCHAR));
+        else
+            Status = StringCbCatW(target, len, layer);
+    }
+
+    return NT_SUCCESS(Status);
+}
+
+
+/**
+ * Determine if we allow permission layers to apply on this file.
+ *
+ * @param [in]  Path    Full pathname of the file, only the drive part is used.
+ *
+ * @return  TRUE if we allow permission layer, FALSE if not.
+ */
+BOOL WINAPI AllowPermLayer(PCWSTR Path)
+{
+    WCHAR tmp[] = { 'A',':','\\', 0 };
+    ULONG type;
+    if (!Path)
+    {
+        SHIM_ERR("Invalid argument\n");
+        return FALSE;
+    }
+    switch (Path[1])
+    {
+    case L':':
+        break;
+    case L'\\':
+        SHIM_INFO("\"%S\" is a network path.\n", Path);
+        return FALSE;
+    default:
+        SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path);
+        return FALSE;
+    }
+    tmp[0] = Path[0];
+    type = GetDriveTypeW(tmp);
+    if (type == DRIVE_REMOTE)
+    {
+        /* The logging here indicates that it does not like a CDROM or removable media, but it only
+            seems to bail out on a media that reports it is remote...
+            I have included correct logging, I doubt anyone would parse the logging, so this shouldnt break anything. */
+        SHIM_INFO("\"%S\" is on a remote drive.\n", Path);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/**
+ * Read the layers specified for the application.
+ *
+ * @param [in]  wszPath     Full pathname of the file.
+ * @param [out] pwszLayers  On return, the layers set on the file.
+ * @param   pdwBytes        The size of the pwszLayers buffer in bytes, and on return the size of
+ *                          the data written (in bytes)
+ * @param [in]  dwFlags     The flags, [GPLK_USER | GPLK_MACHINE].
+ *
+ * @return  TRUE if it succeeds, FALSE if it fails.
+ */
+BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwBytes, DWORD dwFlags)
+{
+    BOOL Result = FALSE;
+    SDB_TMP_STR LongPath;
+    DWORD dwBytes, dwTotal = 0;
+    if (!wszPath || !pdwBytes)
+    {
+        SHIM_ERR("NULL parameter passed for wszPath or pdwBytes.\n");
+        return FALSE;
+    }
+
+    if (!SdbpResolvePath(&LongPath, wszPath))
+        return FALSE;
+    dwBytes = *pdwBytes;
+    if (dwFlags & GPLK_MACHINE)
+    {
+        if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, TRUE))
+        {
+            Result = TRUE;
+            dwTotal = dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */
+            pwszLayers += dwTotal / sizeof(WCHAR);
+            dwBytes = *pdwBytes - dwBytes;
+            if (dwFlags & GPLK_USER)
+            {
+                *(pwszLayers++) = L' ';
+                *pwszLayers = L'\0';
+                dwBytes -= sizeof(WCHAR);
+                dwTotal += sizeof(WCHAR);
+            }
+        }
+    }
+    if (dwFlags & GPLK_USER)
+    {
+        if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, FALSE))
+        {
+            Result = TRUE;
+            dwTotal += dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */
+        }
+        else if (dwTotal > 0 && pwszLayers[-1] == L' ')
+        {
+            pwszLayers[-1] = '\0';
+            dwTotal -= sizeof(WCHAR);
+        }
+    }
+    if (dwTotal)
+        dwTotal += sizeof(WCHAR);
+    *pdwBytes = dwTotal;
+    SdbpFreeTempStr(&LongPath);
+    return Result;
+}
+
+/**
+ * Set or clear the Layer key.
+ *
+ * @param [in]  wszPath     Full pathname of the file.
+ * @param [in]  wszLayers   The layers to add (space separated), or an empty string / NULL to
+ *                          remove all layers.
+ * @param [in]  bMachine    TRUE to machine.
+ *
+ * @return  TRUE if it succeeds, FALSE if it fails.
+ */
+BOOL WINAPI SdbSetPermLayerKeys(PCWSTR wszPath, PCWSTR wszLayers, BOOL bMachine)
+{
+    UNICODE_STRING FullKey;
+    SDB_TMP_STR LongPath;
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+
+    if (!wszLayers || *wszLayers == '\0')
+        return SdbDeletePermLayerKeys(wszPath, bMachine);
+
+    if (!SdbpResolvePath(&LongPath, wszPath))
+        return FALSE;
+
+    Status = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle);
+    if (NT_SUCCESS(Status))
+    {
+        Status = NtSetValueKey(KeyHandle, &LongPath.Str, 0, REG_SZ, (PVOID)wszLayers, (wcslen(wszLayers)+1) * sizeof(WCHAR));
+        if (!NT_SUCCESS(Status))
+        {
+            SHIM_INFO("Failed to write a value to Key \"%wZ\" Status 0x%lx\n", &FullKey, Status);
+            if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+                Status = STATUS_SUCCESS;
+        }
+        NtClose(KeyHandle);
+        SdbFree(FullKey.Buffer);
+    }
+    SdbpFreeTempStr(&LongPath);
+    return NT_SUCCESS(Status);
+}
+
+/**
+ * Adds or removes a single layer entry.
+ *
+ * @param [in]  wszPath     Full pathname of the file.
+ * @param [in]  wszLayer    The layer to add or remove.
+ * @param [in]  dwFlags     Additional flags to add / remove [LAYER_APPLY_TO_SYSTEM_EXES | ???].
+ * @param [in]  bMachine    When TRUE, the setting applies to all users, when FALSE only applies
+ *                          to the current user.
+ * @param [in]  bEnable     TRUE to enable, FALSE to disable a layer / flag specified.
+ *
+ * @return  TRUE if it succeeds, FALSE if it fails.
+ */
+BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable)
+{
+    WCHAR fullLayer[MAX_LAYER_LENGTH] = { 0 };
+    WCHAR newLayer[MAX_LAYER_LENGTH] = { 0 };
+    DWORD dwBytes = sizeof(fullLayer), dwWriteFlags = 0;
+    PWSTR start, p;
+
+    if (!wszLayer)
+    {
+        SHIM_ERR("Invalid argument\n");
+        return FALSE;
+    }
+    if (dwFlags & ~(LAYER_APPLY_TO_SYSTEM_EXES | LAYER_UNK_FLAG2))
+    {
+        SHIM_ERR("Invalid flags\n");
+        return FALSE;
+    }
+    p = wcspbrk(wszLayer, DISALLOWED_LAYER_CHARS);
+    if (p)
+    {
+        switch (*p)
+        {
+        case ' ':
+            SHIM_ERR("Only one layer can be passed in at a time.\n");
+            return FALSE;
+        case '#':
+        case '!':
+            SHIM_ERR("Flags cannot be passed in with the layer name.\n");
+            return FALSE;
+        }
+    }
+    if (!SdbGetPermLayerKeys(wszPath, fullLayer, &dwBytes, bMachine ? GPLK_MACHINE : GPLK_USER))
+    {
+        fullLayer[0] = '\0';
+        dwBytes = sizeof(fullLayer);
+    }
+
+    start = fullLayer;
+    while (*start == '!' || *start == '#' || *start == ' ' || *start == '\t')
+    {
+        if (*start == '#')
+            dwWriteFlags |= LAYER_APPLY_TO_SYSTEM_EXES;
+        else if (*start == '!')
+            dwWriteFlags |= LAYER_UNK_FLAG2;
+        start++;
+    }
+    if (bEnable)
+        dwWriteFlags |= dwFlags;
+    else
+        dwWriteFlags &= ~dwFlags;
+
+    p = newLayer;
+    if (dwWriteFlags & LAYER_UNK_FLAG2)
+        *(p++) = '!';
+    if (dwWriteFlags & LAYER_APPLY_TO_SYSTEM_EXES)
+        *(p++) = '#';
+
+    do
+    {
+        while (*start == ' ' || *start == '\t')
+            ++start;
+
+        if (*start == '\0')
+            break;
+        p = wcspbrk(start, LAYER_SEPARATORS);
+        if (!SdbpMatchLayer(start, p, wszLayer))
+        {
+            SdbpAppendLayer(newLayer, sizeof(newLayer), start, p);
+        }
+        start = p + 1;
+    } while (p);
+
+    if (bEnable && wszLayer[0])
+    {
+        SdbpAppendLayer(newLayer, sizeof(newLayer), wszLayer, NULL);
+    }
+
+    return SdbSetPermLayerKeys(wszPath, newLayer, bMachine);
+}
diff --git a/reactos/dll/appcompat/apphelp/sdbapi.c b/reactos/dll/appcompat/apphelp/sdbapi.c
new file mode 100644 (file)
index 0000000..fd2d0e6
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2011 André Hentschel
+ * Copyright 2013 Mislav Blažević
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_NO_STATUS
+#include "windows.h"
+#include "ntndk.h"
+#include "strsafe.h"
+#include "apphelp.h"
+
+#include "wine/unicode.h"
+
+
+static HANDLE SdbpHeap(void);
+
+#if SDBAPI_DEBUG_ALLOC
+
+typedef struct SHIM_ALLOC_ENTRY
+{
+    PVOID Address;
+    SIZE_T Size;
+    int Line;
+    const char* File;
+    PVOID Next;
+    PVOID Prev;
+} SHIM_ALLOC_ENTRY, *PSHIM_ALLOC_ENTRY;
+
+
+static RTL_AVL_TABLE g_SdbpAllocationTable;
+
+
+static RTL_GENERIC_COMPARE_RESULTS
+NTAPI ShimAllocCompareRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct)
+{
+    PVOID First = ((PSHIM_ALLOC_ENTRY)FirstStruct)->Address;
+    PVOID Second = ((PSHIM_ALLOC_ENTRY)SecondStruct)->Address;
+
+    if (First < Second)
+        return GenericLessThan;
+    else if (First == Second)
+        return GenericEqual;
+    return GenericGreaterThan;
+}
+
+static PVOID NTAPI ShimAllocAllocateRoutine(_In_ PRTL_AVL_TABLE Table, _In_ CLONG ByteSize)
+{
+    return HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, ByteSize);
+}
+
+static VOID NTAPI ShimAllocFreeRoutine(_In_ PRTL_AVL_TABLE Table, _In_ PVOID Buffer)
+{
+    HeapFree(SdbpHeap(), 0, Buffer);
+}
+
+static void SdbpInsertAllocation(PVOID address, SIZE_T size, int line, const char* file)
+{
+    SHIM_ALLOC_ENTRY Entry = {0};
+
+    Entry.Address = address;
+    Entry.Size = size;
+    Entry.Line = line;
+    Entry.File = file;
+    RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Entry, sizeof(Entry), NULL);
+}
+
+static void SdbpUpdateAllocation(PVOID address, PVOID newaddress, SIZE_T size, int line, const char* file)
+{
+    SHIM_ALLOC_ENTRY Lookup = {0};
+    PSHIM_ALLOC_ENTRY Entry;
+    Lookup.Address = address;
+    Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
+
+    if (address == newaddress)
+    {
+        Entry->Size = size;
+    }
+    else
+    {
+        Lookup.Address = newaddress;
+        Lookup.Size = size;
+        Lookup.Line = line;
+        Lookup.File = file;
+        Lookup.Prev = address;
+        RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup, sizeof(Lookup), NULL);
+        Entry->Next = newaddress;
+    }
+}
+
+static void SdbpRemoveAllocation(PVOID address, int line, const char* file)
+{
+    char buf[512];
+    SHIM_ALLOC_ENTRY Lookup = {0};
+    PSHIM_ALLOC_ENTRY Entry;
+
+    sprintf(buf, "\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file, line);
+    OutputDebugStringA(buf);
+
+    Lookup.Address = address;
+    while (Lookup.Address)
+    {
+        Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup);
+        if (Entry)
+        {
+            Lookup = *Entry;
+            RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable, Entry);
+
+            sprintf(buf, " > %s(%d): %s%sAlloc( %d ) ==> %p\r\n", Lookup.File, Lookup.Line,
+                Lookup.Next ? "Invalidated " : "", Lookup.Prev ? "Re" : "", Lookup.Size, Lookup.Address);
+            OutputDebugStringA(buf);
+            Lookup.Address = Lookup.Prev;
+        }
+        else
+        {
+            Lookup.Address = NULL;
+        }
+    }
+    sprintf(buf, "\r\n===============\r\n");
+    OutputDebugStringA(buf);
+}
+
+#endif
+
+static HANDLE g_Heap;
+void SdbpHeapInit(void)
+{
+#if SDBAPI_DEBUG_ALLOC
+    RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine,
+        ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL);
+#endif
+    g_Heap = HeapCreate(0, 0x10000, 0);
+}
+
+void SdbpHeapDeinit(void)
+{
+#if SDBAPI_DEBUG_ALLOC
+    if (g_SdbpAllocationTable.NumberGenericTableElements != 0)
+        __debugbreak();
+#endif
+    HeapDestroy(g_Heap);
+}
+
+DWORD SdbpStrlen(PCWSTR string)
+{
+    return (lstrlenW(string) + 1) * sizeof(WCHAR);
+}
+
+static HANDLE SdbpHeap(void)
+{
+    return g_Heap;
+}
+
+LPVOID SdbpAlloc(SIZE_T size
+#if SDBAPI_DEBUG_ALLOC
+    , int line, const char* file
+#endif
+    )
+{
+    LPVOID mem = HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, size);
+#if SDBAPI_DEBUG_ALLOC
+    SdbpInsertAllocation(mem, size, line, file);
+#endif
+    return mem;
+}
+
+LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size
+#if SDBAPI_DEBUG_ALLOC
+    , int line, const char* file
+#endif
+    )
+{
+    LPVOID newmem = HeapReAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, mem, size);
+#if SDBAPI_DEBUG_ALLOC
+    SdbpUpdateAllocation(mem, newmem, size, line, file);
+#endif
+    return newmem;
+}
+
+void SdbpFree(LPVOID mem
+#if SDBAPI_DEBUG_ALLOC
+    , int line, const char* file
+#endif
+    )
+{
+#if SDBAPI_DEBUG_ALLOC
+    SdbpRemoveAllocation(mem, line, file);
+#endif
+    HeapFree(SdbpHeap(), 0, mem);
+}