mirror of
https://github.com/reactos/reactos.git
synced 2024-10-06 01:13:38 +00:00
5c05a29d3d
These functions simply call into the Base* functions, having a prototype that is compatible with rundll32 CORE-11301
330 lines
9.2 KiB
C
330 lines
9.2 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-2019 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'\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;
|
|
}
|
|
|
|
|
|
/**
|
|
* @name SdbRegisterDatabaseEx
|
|
* Register an application compatibility database
|
|
*
|
|
* @param pszDatabasePath The database. Required
|
|
* @param dwDatabaseType The database type. SDB_DATABASE_*
|
|
* @param pTimeStamp The timestamp. When this argument is not provided, the system time is used.
|
|
* @return TRUE on success, or FALSE on failure.
|
|
*/
|
|
BOOL WINAPI SdbRegisterDatabaseEx(
|
|
_In_ LPCTSTR pszDatabasePath,
|
|
_In_ DWORD dwDatabaseType,
|
|
_In_opt_ PULONGLONG pTimeStamp)
|
|
{
|
|
SHIM_ERR("UNIMPLEMENTED, pszDatabasePath=%ws, dwDatabaseType=0x%x, pTimeStamp=%p\n",
|
|
pszDatabasePath, dwDatabaseType, pTimeStamp);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* @name SdbRegisterDatabase
|
|
* Register an application compatibility database
|
|
*
|
|
* @param pszDatabasePath The database. Required
|
|
* @param dwDatabaseType The database type. SDB_DATABASE_*
|
|
* @return TRUE on success, or FALSE on failure.
|
|
*/
|
|
BOOL WINAPI SdbRegisterDatabase(
|
|
_In_ LPCTSTR pszDatabasePath,
|
|
_In_ DWORD dwDatabaseType)
|
|
{
|
|
return SdbRegisterDatabaseEx(pszDatabasePath, dwDatabaseType, NULL);
|
|
}
|
|
|
|
|
|
/**
|
|
* @name SdbUnregisterDatabase
|
|
*
|
|
*
|
|
* @param pguidDB
|
|
* @return
|
|
*/
|
|
BOOL WINAPI SdbUnregisterDatabase(_In_ GUID *pguidDB)
|
|
{
|
|
SHIM_ERR("UNIMPLEMENTED, pguidDB = %p\n", pguidDB);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* kernel32.dll */
|
|
BOOL WINAPI BaseDumpAppcompatCache(VOID);
|
|
BOOL WINAPI BaseFlushAppcompatCache(VOID);
|
|
|
|
|
|
/**
|
|
* @name ShimDumpCache
|
|
* Dump contents of the shim cache.
|
|
*
|
|
* @param hwnd Unused, pass 0
|
|
* @param hInstance Unused, pass 0
|
|
* @param lpszCmdLine Unused, pass 0
|
|
* @param nCmdShow Unused, pass 0
|
|
* @return
|
|
*/
|
|
BOOL WINAPI ShimDumpCache(HWND hwnd, HINSTANCE hInstance, LPCSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
return BaseDumpAppcompatCache();
|
|
}
|
|
|
|
/**
|
|
* @name ShimFlushCache
|
|
* Flush the shim cache. Call this after installing a new shim database
|
|
*
|
|
* @param hwnd Unused, pass 0
|
|
* @param hInstance Unused, pass 0
|
|
* @param lpszCmdLine Unused, pass 0
|
|
* @param nCmdShow Unused, pass 0
|
|
* @return
|
|
*/
|
|
BOOL WINAPI ShimFlushCache(HWND hwnd, HINSTANCE hInstance, LPCSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
return BaseFlushAppcompatCache();
|
|
}
|