90bc9fd5715fda70beeb56e065d8e24151c359f5
[reactos.git] / reactos / dll / appcompat / apphelp / apphelp.c
1 /*
2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Blažević
4 * Copyright 2015-2017 Mark Jansen
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define WIN32_NO_STATUS
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winver.h"
25 #include "strsafe.h"
26 #include "apphelp.h"
27 #include "ndk/rtlfuncs.h"
28 #include "ndk/kdtypes.h"
29
30
31 /* from dpfilter.h */
32 #define DPFLTR_APPCOMPAT_ID 123
33
34 #ifndef NT_SUCCESS
35 #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
36 #endif
37
38 ULONG g_ShimDebugLevel = 0xffffffff;
39 HMODULE g_hInstance;
40
41 void ApphelppInitDebugLevel(void)
42 {
43 static const UNICODE_STRING DebugKey = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
44 UNICODE_STRING DebugValue;
45 NTSTATUS Status;
46 ULONG NewLevel = SHIM_ERR;
47 WCHAR Buffer[40];
48
49 RtlInitEmptyUnicodeString(&DebugValue, Buffer, sizeof(Buffer));
50
51 Status = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue);
52
53 if (NT_SUCCESS(Status))
54 {
55 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel)))
56 NewLevel = 0;
57 }
58 g_ShimDebugLevel = NewLevel;
59 }
60
61
62 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
63 {
64 switch (reason)
65 {
66 #ifndef __REACTOS__
67 case DLL_WINE_PREATTACH:
68 return FALSE; /* prefer native version */
69 #endif
70 case DLL_PROCESS_ATTACH:
71 g_hInstance = hinst;
72 DisableThreadLibraryCalls( hinst );
73 SdbpHeapInit();
74 break;
75 case DLL_PROCESS_DETACH:
76 SdbpHeapDeinit();
77 break;
78 }
79 return TRUE;
80 }
81
82 BOOL WINAPI ApphelpCheckInstallShieldPackage(void* ptr, LPCWSTR path)
83 {
84 SHIM_WARN("stub: ptr=%p, path='%S'\r\n", ptr, path);
85 return TRUE;
86 }
87
88
89 BOOL WINAPI ApphelpCheckShellObject(REFCLSID ObjectCLSID, BOOL bShimIfNecessary, ULONGLONG *pullFlags)
90 {
91 WCHAR GuidString[100];
92 if (!ObjectCLSID || !SdbGUIDToString(ObjectCLSID, GuidString, 100))
93 GuidString[0] = L'\0';
94 SHIM_WARN("stub: ObjectCLSID='%S', bShimIfNecessary=%d, pullFlags=%p)\n", GuidString, bShimIfNecessary, pullFlags);
95
96 if (pullFlags)
97 *pullFlags = 0;
98
99 return TRUE;
100 }
101
102 /**
103 * Outputs diagnostic info.
104 *
105 * @param [in] Level The level to log this message with, choose any of [SHIM_ERR,
106 * SHIM_WARN, SHIM_INFO].
107 * @param [in] FunctionName The function this log should be attributed to.
108 * @param [in] Format The format string.
109 * @param ... Variable arguments providing additional information.
110 *
111 * @return Success: TRUE Failure: FALSE.
112 */
113 BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...)
114 {
115 char Buffer[512];
116 va_list ArgList;
117 char* Current = Buffer;
118 const char* LevelStr;
119 size_t Length = sizeof(Buffer);
120
121 if (g_ShimDebugLevel == 0xffffffff)
122 ApphelppInitDebugLevel();
123
124 if (Level > g_ShimDebugLevel)
125 return FALSE;
126
127 switch (Level)
128 {
129 case SHIM_ERR:
130 LevelStr = "Err ";
131 Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL);
132 break;
133 case SHIM_WARN:
134 LevelStr = "Warn";
135 Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL);
136 break;
137 case SHIM_INFO:
138 LevelStr = "Info";
139 Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
140 break;
141 default:
142 LevelStr = "User";
143 Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL);
144 break;
145 }
146 StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName);
147
148 va_start(ArgList, Format);
149 StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
150 va_end(ArgList);
151
152 #if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
153 return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer));
154 #else
155 OutputDebugStringA(Buffer);
156 return TRUE;
157 #endif
158 }
159
160
161 #define APPHELP_DONTWRITE_REASON 2
162 #define APPHELP_CLEARBITS 0x100 /* TODO: Investigate */
163 #define APPHELP_IGNORE_ENVIRONMENT 0x400
164
165 #define APPHELP_VALID_RESULT 0x10000
166 #define APPHELP_RESULT_NOTFOUND 0x20000
167 #define APPHELP_RESULT_FOUND 0x40000
168
169 /**
170 * Lookup Shims / Fixes for the specified application
171 *
172 * @param [in] FileHandle Handle to the file to check.
173 * @param [in] Unk1
174 * @param [in] Unk2
175 * @param [in] ApplicationName Exe to check
176 * @param [in] Environment The environment variables to use, or NULL to use the current environment.
177 * @param [in] ExeType Exe type (MACHINE_TYPE_XXXX)
178 * @param [in,out] Reason Input/output flags
179 * @param [in] SdbQueryAppCompatData The resulting data.
180 * @param [in] SdbQueryAppCompatDataSize The resulting data size.
181 * @param [in] SxsData TODO
182 * @param [in] SxsDataSize TODO
183 * @param [in] FusionFlags TODO
184 * @param [in] SomeFlag1 TODO
185 * @param [in] SomeFlag2 TODO
186 *
187 * @return TRUE if the application is allowed to run.
188 */
189 BOOL
190 WINAPI
191 ApphelpCheckRunAppEx(
192 _In_ HANDLE FileHandle,
193 _In_opt_ PVOID Unk1,
194 _In_opt_ PVOID Unk2,
195 _In_opt_z_ PWCHAR ApplicationName,
196 _In_opt_ PVOID Environment,
197 _In_opt_ USHORT ExeType,
198 _Inout_opt_ PULONG Reason,
199 _Out_opt_ PVOID* SdbQueryAppCompatData,
200 _Out_opt_ PULONG SdbQueryAppCompatDataSize,
201 _Out_opt_ PVOID* SxsData,
202 _Out_opt_ PULONG SxsDataSize,
203 _Out_opt_ PULONG FusionFlags,
204 _Out_opt_ PULONG64 SomeFlag1,
205 _Out_opt_ PULONG SomeFlag2)
206 {
207 SDBQUERYRESULT* result = NULL;
208 HSDB hsdb = NULL;
209 DWORD dwFlags = 0;
210
211 if (SxsData)
212 *SxsData = NULL;
213 if (SxsDataSize)
214 *SxsDataSize = 0;
215 if (FusionFlags)
216 *FusionFlags = 0;
217 if (SomeFlag1)
218 *SomeFlag1 = 0;
219 if (SomeFlag2)
220 *SomeFlag2 = 0;
221 if (Reason)
222 dwFlags = *Reason;
223
224 dwFlags &= ~APPHELP_CLEARBITS;
225
226 *SdbQueryAppCompatData = result = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SDBQUERYRESULT));
227 if (SdbQueryAppCompatDataSize)
228 *SdbQueryAppCompatDataSize = sizeof(*result);
229
230
231 hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
232 if (hsdb)
233 {
234 BOOL FoundMatch;
235 DWORD MatchingExeFlags = 0;
236
237 if (dwFlags & APPHELP_IGNORE_ENVIRONMENT)
238 MatchingExeFlags |= SDBGMEF_IGNORE_ENVIRONMENT;
239
240 FoundMatch = SdbGetMatchingExe(hsdb, ApplicationName, NULL, Environment, MatchingExeFlags, result);
241 if (FileHandle != INVALID_HANDLE_VALUE)
242 {
243 dwFlags |= APPHELP_VALID_RESULT;
244 dwFlags |= (FoundMatch ? APPHELP_RESULT_FOUND : APPHELP_RESULT_NOTFOUND);
245 }
246
247 SdbReleaseDatabase(hsdb);
248 }
249
250 if (Reason && !(dwFlags & APPHELP_DONTWRITE_REASON))
251 *Reason = dwFlags;
252
253
254 /* We should _ALWAYS_ return TRUE here, unless we want to block an application from starting! */
255 return TRUE;
256 }
257
258