xref: /reactos/dll/appcompat/apphelp/apphelp.c (revision 0dd71438)
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 
243