mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[APPHELP]
- 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
This commit is contained in:
parent
d4705d3a33
commit
3a5f8b5d7e
8 changed files with 1162 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
|||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(appcompat)
|
||||
add_subdirectory(cpl)
|
||||
add_subdirectory(directx)
|
||||
add_subdirectory(keyboard)
|
||||
|
|
2
reactos/dll/appcompat/CMakeLists.txt
Normal file
2
reactos/dll/appcompat/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
add_subdirectory(apphelp)
|
20
reactos/dll/appcompat/apphelp/CMakeLists.txt
Normal file
20
reactos/dll/appcompat/apphelp/CMakeLists.txt
Normal file
|
@ -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)
|
135
reactos/dll/appcompat/apphelp/apphelp.c
Normal file
135
reactos/dll/appcompat/apphelp/apphelp.c
Normal file
|
@ -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));
|
||||
}
|
||||
|
71
reactos/dll/appcompat/apphelp/apphelp.h
Normal file
71
reactos/dll/appcompat/apphelp/apphelp.h
Normal file
|
@ -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
|
175
reactos/dll/appcompat/apphelp/apphelp.spec
Normal file
175
reactos/dll/appcompat/apphelp/apphelp.spec
Normal file
|
@ -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)
|
554
reactos/dll/appcompat/apphelp/layer.c
Normal file
554
reactos/dll/appcompat/apphelp/layer.c
Normal file
|
@ -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);
|
||||
}
|
204
reactos/dll/appcompat/apphelp/sdbapi.c
Normal file
204
reactos/dll/appcompat/apphelp/sdbapi.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue