[DEVMGR] Hackfix CORE-5643
[reactos.git] / dll / appcompat / apphelp / apphelp.c
1 /*
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-2018 Mark Jansen (mark.jansen@reactos.org)
8 */
9
10 #define WIN32_NO_STATUS
11 #include "windef.h"
12 #include "winbase.h"
13 #include "winver.h"
14 #include "strsafe.h"
15 #include "apphelp.h"
16 #include "ndk/rtlfuncs.h"
17 #include "ndk/kdtypes.h"
18
19
20 /* from dpfilter.h */
21 #define DPFLTR_APPCOMPAT_ID 123
22
23 #ifndef NT_SUCCESS
24 #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
25 #endif
26
27 ULONG g_ShimDebugLevel = 0xffffffff;
28 HMODULE g_hInstance;
29
30 void ApphelppInitDebugLevel(void)
31 {
32 static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
33 UNICODE_STRING DebugValue;
34 NTSTATUS Status;
35 ULONG NewLevel = SHIM_ERR;
36 WCHAR Buffer[40];
37
38 RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
39
40 Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
41
42 if (NT_SUCCESS(Status))
43 {
44 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
45 NewLevel = SHIM_ERR;
46 }
47 g_ShimDebugLevel = NewLevel;
48 }
49
50
51 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
52 {
53 switch (reason)
54 {
55 case DLL_PROCESS_ATTACH:
56 g_hInstance = hinst;
57 DisableThreadLibraryCalls( hinst );
58 SdbpHeapInit();
59 break;
60 case DLL_PROCESS_DETACH:
61 SdbpHeapDeinit();
62 break;
63 }
64 return TRUE;
65 }
66
67 BOOL WINAPI ApphelpCheckInstallShieldPackage(void* ptr, LPCWSTR path)
68 {
69 SHIM_WARN("stub: ptr=%p, path='%S'\r\n", ptr, path);
70 return TRUE;
71 }
72
73
74 BOOL WINAPI ApphelpCheckShellObject(REFCLSID ObjectCLSID, BOOL bShimIfNecessary, ULONGLONG *pullFlags)
75 {
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);
80
81 if (pullFlags)
82 *pullFlags = 0;
83
84 return TRUE;
85 }
86
87 /**
88 * Outputs diagnostic info.
89 *
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.
95 *
96 * @return Success: TRUE Failure: FALSE.
97 */
98 BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...)
99 {
100 char Buffer[512];
101 va_list ArgList;
102 char* Current = Buffer;
103 const char* LevelStr;
104 size_t Length = sizeof(Buffer);
105
106 if (g_ShimDebugLevel == 0xffffffff)
107 ApphelppInitDebugLevel();
108
109 if (Level > g_ShimDebugLevel)
110 return FALSE;
111
112 switch (Level)
113 {
114 case SHIM_ERR:
115 LevelStr = "Err ";
116 Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL);
117 break;
118 case SHIM_WARN:
119 LevelStr = "Warn";
120 Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL);
121 break;
122 case SHIM_INFO:
123 LevelStr = "Info";
124 Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
125 break;
126 default:
127 LevelStr = "User";
128 Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
129 break;
130 }
131 StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName);
132
133 va_start(ArgList, Format);
134 StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
135 va_end(ArgList);
136
137 #if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
138 return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
139 #else
140 DbgPrint("%s", Buffer);
141 return TRUE;
142 #endif
143 }
144
145
146 #define APPHELP_DONTWRITE_REASON 2
147 #define APPHELP_CLEARBITS 0x100 /* TODO: Investigate */
148 #define APPHELP_IGNORE_ENVIRONMENT 0x400
149
150 #define APPHELP_VALID_RESULT 0x10000
151 #define APPHELP_RESULT_NOTFOUND 0x20000
152 #define APPHELP_RESULT_FOUND 0x40000
153
154 /**
155 * Lookup Shims / Fixes for the specified application
156 *
157 * @param [in] FileHandle Handle to the file to check.
158 * @param [in] Unk1
159 * @param [in] Unk2
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
171 *
172 * @return TRUE if the application is allowed to run.
173 */
174 BOOL
175 WINAPI
176 ApphelpCheckRunAppEx(
177 _In_ HANDLE FileHandle,
178 _In_opt_ PVOID Unk1,
179 _In_opt_ PVOID Unk2,
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)
191 {
192 SDBQUERYRESULT* result = NULL;
193 HSDB hsdb = NULL;
194 DWORD dwFlags = 0;
195
196 if (SxsData)
197 *SxsData = NULL;
198 if (SxsDataSize)
199 *SxsDataSize = 0;
200 if (FusionFlags)
201 *FusionFlags = 0;
202 if (SomeFlag1)
203 *SomeFlag1 = 0;
204 if (SomeFlag2)
205 *SomeFlag2 = 0;
206 if (Reason)
207 dwFlags = *Reason;
208
209 dwFlags &= ~APPHELP_CLEARBITS;
210
211 *SdbQueryAppCompatData = result = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SDBQUERYRESULT));
212 if (SdbQueryAppCompatDataSize)
213 *SdbQueryAppCompatDataSize = sizeof(*result);
214
215
216 hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
217 if (hsdb)
218 {
219 BOOL FoundMatch;
220 DWORD MatchingExeFlags = 0;
221
222 if (dwFlags & APPHELP_IGNORE_ENVIRONMENT)
223 MatchingExeFlags |= SDBGMEF_IGNORE_ENVIRONMENT;
224
225 FoundMatch = SdbGetMatchingExe(hsdb, ApplicationName, NULL, Environment, MatchingExeFlags, result);
226 if (FileHandle != INVALID_HANDLE_VALUE)
227 {
228 dwFlags |= APPHELP_VALID_RESULT;
229 dwFlags |= (FoundMatch ? APPHELP_RESULT_FOUND : APPHELP_RESULT_NOTFOUND);
230 }
231
232 SdbReleaseDatabase(hsdb);
233 }
234
235 if (Reason && !(dwFlags & APPHELP_DONTWRITE_REASON))
236 *Reason = dwFlags;
237
238
239 /* We should _ALWAYS_ return TRUE here, unless we want to block an application from starting! */
240 return TRUE;
241 }
242