2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: apphelp entrypoint / generic interface functions
5 * COPYRIGHT: Copyright 2011 André Hentschel
6 * Copyright 2013 Mislav Blaževic
7 * Copyright 2015-2019 Mark Jansen (mark.jansen@reactos.org)
10 #define WIN32_NO_STATUS
16 #include "ndk/rtlfuncs.h"
17 #include "ndk/kdtypes.h"
21 #define DPFLTR_APPCOMPAT_ID 123
24 #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
27 ULONG g_ShimDebugLevel
= 0xffffffff;
30 void ApphelppInitDebugLevel(void)
32 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIM_DEBUG_LEVEL");
33 UNICODE_STRING DebugValue
;
35 ULONG NewLevel
= SHIM_ERR
;
38 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
40 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
42 if (NT_SUCCESS(Status
))
44 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
47 g_ShimDebugLevel
= NewLevel
;
51 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
55 case DLL_PROCESS_ATTACH
:
57 DisableThreadLibraryCalls( hinst
);
60 case DLL_PROCESS_DETACH
:
67 BOOL WINAPI
ApphelpCheckInstallShieldPackage(void* ptr
, LPCWSTR path
)
69 SHIM_WARN("stub: ptr=%p, path='%S'\n", ptr
, path
);
74 BOOL WINAPI
ApphelpCheckShellObject(REFCLSID ObjectCLSID
, BOOL bShimIfNecessary
, ULONGLONG
*pullFlags
)
76 WCHAR GuidString
[100];
77 if (!ObjectCLSID
|| !SdbGUIDToString(ObjectCLSID
, GuidString
, 100))
78 GuidString
[0] = L
'\0';
79 SHIM_WARN("stub: ObjectCLSID='%S', bShimIfNecessary=%d, pullFlags=%p)\n", GuidString
, bShimIfNecessary
, pullFlags
);
88 * Outputs diagnostic info.
90 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
91 * SHIM_WARN, SHIM_INFO].
92 * @param [in] FunctionName The function this log should be attributed to.
93 * @param [in] Format The format string.
94 * @param ... Variable arguments providing additional information.
96 * @return Success: TRUE Failure: FALSE.
98 BOOL WINAPIV
ShimDbgPrint(SHIM_LOG_LEVEL Level
, PCSTR FunctionName
, PCSTR Format
, ...)
102 char* Current
= Buffer
;
103 const char* LevelStr
;
104 size_t Length
= sizeof(Buffer
);
106 if (g_ShimDebugLevel
== 0xffffffff)
107 ApphelppInitDebugLevel();
109 if (Level
> g_ShimDebugLevel
)
116 Level
= DPFLTR_MASK
| (1 << DPFLTR_ERROR_LEVEL
);
120 Level
= DPFLTR_MASK
| (1 << DPFLTR_WARNING_LEVEL
);
124 Level
= DPFLTR_MASK
| (1 << DPFLTR_INFO_LEVEL
);
128 Level
= DPFLTR_MASK
| (1 << DPFLTR_INFO_LEVEL
);
131 StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s][%-20s] ", LevelStr
, FunctionName
);
133 va_start(ArgList
, Format
);
134 StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
137 #if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
138 return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID
, Level
, "%s", Buffer
));
140 DbgPrint("%s", Buffer
);
146 #define APPHELP_DONTWRITE_REASON 2
147 #define APPHELP_CLEARBITS 0x100 /* TODO: Investigate */
148 #define APPHELP_IGNORE_ENVIRONMENT 0x400
150 #define APPHELP_VALID_RESULT 0x10000
151 #define APPHELP_RESULT_NOTFOUND 0x20000
152 #define APPHELP_RESULT_FOUND 0x40000
155 * Lookup Shims / Fixes for the specified application
157 * @param [in] FileHandle Handle to the file to check.
160 * @param [in] ApplicationName Exe to check
161 * @param [in] Environment The environment variables to use, or NULL to use the current environment.
162 * @param [in] ExeType Exe type (MACHINE_TYPE_XXXX)
163 * @param [in,out] Reason Input/output flags
164 * @param [in] SdbQueryAppCompatData The resulting data.
165 * @param [in] SdbQueryAppCompatDataSize The resulting data size.
166 * @param [in] SxsData TODO
167 * @param [in] SxsDataSize TODO
168 * @param [in] FusionFlags TODO
169 * @param [in] SomeFlag1 TODO
170 * @param [in] SomeFlag2 TODO
172 * @return TRUE if the application is allowed to run.
176 ApphelpCheckRunAppEx(
177 _In_ HANDLE FileHandle
,
180 _In_opt_z_ PWCHAR ApplicationName
,
181 _In_opt_ PVOID Environment
,
182 _In_opt_ USHORT ExeType
,
183 _Inout_opt_ PULONG Reason
,
184 _Out_opt_ PVOID
* SdbQueryAppCompatData
,
185 _Out_opt_ PULONG SdbQueryAppCompatDataSize
,
186 _Out_opt_ PVOID
* SxsData
,
187 _Out_opt_ PULONG SxsDataSize
,
188 _Out_opt_ PULONG FusionFlags
,
189 _Out_opt_ PULONG64 SomeFlag1
,
190 _Out_opt_ PULONG SomeFlag2
)
192 SDBQUERYRESULT
* result
= NULL
;
209 dwFlags
&= ~APPHELP_CLEARBITS
;
211 *SdbQueryAppCompatData
= result
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SDBQUERYRESULT
));
212 if (SdbQueryAppCompatDataSize
)
213 *SdbQueryAppCompatDataSize
= sizeof(*result
);
216 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
220 DWORD MatchingExeFlags
= 0;
222 if (dwFlags
& APPHELP_IGNORE_ENVIRONMENT
)
223 MatchingExeFlags
|= SDBGMEF_IGNORE_ENVIRONMENT
;
225 FoundMatch
= SdbGetMatchingExe(hsdb
, ApplicationName
, NULL
, Environment
, MatchingExeFlags
, result
);
226 if (FileHandle
!= INVALID_HANDLE_VALUE
)
228 dwFlags
|= APPHELP_VALID_RESULT
;
229 dwFlags
|= (FoundMatch
? APPHELP_RESULT_FOUND
: APPHELP_RESULT_NOTFOUND
);
232 SdbReleaseDatabase(hsdb
);
235 if (Reason
&& !(dwFlags
& APPHELP_DONTWRITE_REASON
))
239 /* We should _ALWAYS_ return TRUE here, unless we want to block an application from starting! */
245 * @name SdbRegisterDatabaseEx
246 * Register an application compatibility database
248 * @param pszDatabasePath The database. Required
249 * @param dwDatabaseType The database type. SDB_DATABASE_*
250 * @param pTimeStamp The timestamp. When this argument is not provided, the system time is used.
251 * @return TRUE on success, or FALSE on failure.
253 BOOL WINAPI
SdbRegisterDatabaseEx(
254 _In_ LPCTSTR pszDatabasePath
,
255 _In_ DWORD dwDatabaseType
,
256 _In_opt_ PULONGLONG pTimeStamp
)
258 SHIM_ERR("UNIMPLEMENTED, pszDatabasePath=%ws, dwDatabaseType=0x%x, pTimeStamp=%p\n",
259 pszDatabasePath
, dwDatabaseType
, pTimeStamp
);
266 * @name SdbRegisterDatabase
267 * Register an application compatibility database
269 * @param pszDatabasePath The database. Required
270 * @param dwDatabaseType The database type. SDB_DATABASE_*
271 * @return TRUE on success, or FALSE on failure.
273 BOOL WINAPI
SdbRegisterDatabase(
274 _In_ LPCTSTR pszDatabasePath
,
275 _In_ DWORD dwDatabaseType
)
277 return SdbRegisterDatabaseEx(pszDatabasePath
, dwDatabaseType
, NULL
);
282 * @name SdbUnregisterDatabase
288 BOOL WINAPI
SdbUnregisterDatabase(_In_ GUID
*pguidDB
)
290 SHIM_ERR("UNIMPLEMENTED, pguidDB = %p\n", pguidDB
);
297 BOOL WINAPI
BaseDumpAppcompatCache(VOID
);
298 BOOL WINAPI
BaseFlushAppcompatCache(VOID
);
302 * @name ShimDumpCache
303 * Dump contents of the shim cache.
305 * @param hwnd Unused, pass 0
306 * @param hInstance Unused, pass 0
307 * @param lpszCmdLine Unused, pass 0
308 * @param nCmdShow Unused, pass 0
311 BOOL WINAPI
ShimDumpCache(HWND hwnd
, HINSTANCE hInstance
, LPCSTR lpszCmdLine
, int nCmdShow
)
313 return BaseDumpAppcompatCache();
317 * @name ShimFlushCache
318 * Flush the shim cache. Call this after installing a new shim database
320 * @param hwnd Unused, pass 0
321 * @param hInstance Unused, pass 0
322 * @param lpszCmdLine Unused, pass 0
323 * @param nCmdShow Unused, pass 0
326 BOOL WINAPI
ShimFlushCache(HWND hwnd
, HINSTANCE hInstance
, LPCSTR lpszCmdLine
, int nCmdShow
)
328 return BaseFlushAppcompatCache();