reactos/dll/appcompat/apphelp/apphelp.c

243 lines
7 KiB
C

/*
* PROJECT: ReactOS Application compatibility module
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: apphelp entrypoint / generic interface functions
* COPYRIGHT: Copyright 2011 André Hentschel
* Copyright 2013 Mislav Blaževic
* Copyright 2015-2018 Mark Jansen (mark.jansen@reactos.org)
*/
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winver.h"
#include "strsafe.h"
#include "apphelp.h"
#include "ndk/rtlfuncs.h"
#include "ndk/kdtypes.h"
/* from dpfilter.h */
#define DPFLTR_APPCOMPAT_ID 123
#ifndef NT_SUCCESS
#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
#endif
ULONG g_ShimDebugLevel = 0xffffffff;
HMODULE g_hInstance;
void ApphelppInitDebugLevel(void)
{
static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
UNICODE_STRING DebugValue;
NTSTATUS Status;
ULONG NewLevel = SHIM_ERR;
WCHAR Buffer[40];
RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
if (NT_SUCCESS(Status))
{
if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
NewLevel = SHIM_ERR;
}
g_ShimDebugLevel = NewLevel;
}
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
g_hInstance = hinst;
DisableThreadLibraryCalls( hinst );
SdbpHeapInit();
break;
case DLL_PROCESS_DETACH:
SdbpHeapDeinit();
break;
}
return TRUE;
}
BOOL WINAPI ApphelpCheckInstallShieldPackage(void* ptr, LPCWSTR path)
{
SHIM_WARN("stub: ptr=%p, path='%S'\r\n", ptr, path);
return TRUE;
}
BOOL WINAPI ApphelpCheckShellObject(REFCLSID ObjectCLSID, BOOL bShimIfNecessary, ULONGLONG *pullFlags)
{
WCHAR GuidString[100];
if (!ObjectCLSID || !SdbGUIDToString(ObjectCLSID, GuidString, 100))
GuidString[0] = L'\0';
SHIM_WARN("stub: ObjectCLSID='%S', bShimIfNecessary=%d, pullFlags=%p)\n", GuidString, bShimIfNecessary, pullFlags);
if (pullFlags)
*pullFlags = 0;
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;
const char* 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);
#if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
#else
DbgPrint("%s", Buffer);
return TRUE;
#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;
}