2180498319d676afe35671497f313ca27ba9b274
[reactos.git] / reactos / dll / win32 / kernel32 / client / appcache.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/client/appcache.c
5 * PURPOSE: Application Compatibility Cache
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 ULONG g_ShimsEnabled = -1;
19 static BOOL g_ApphelpInitialized = FALSE;
20 static PVOID g_pApphelpCheckRunAppEx;
21 static PVOID g_pSdbPackAppCompatData;
22
23 typedef BOOL (WINAPI *tApphelpCheckRunAppEx)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType, PULONG Reason,
24 PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize,
25 PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2);
26 typedef BOOL (WINAPI *tSdbPackAppCompatData)(PVOID hsdb, PVOID pQueryResult, PVOID* ppData, DWORD *dwSize);
27
28 #define APPHELP_VALID_RESULT 0x10000
29 #define APPHELP_RESULT_NOTFOUND 0x20000
30 #define APPHELP_RESULT_FOUND 0x40000
31
32
33 /* FUNCTIONS ******************************************************************/
34
35 BOOLEAN
36 WINAPI
37 IsShimInfrastructureDisabled(VOID)
38 {
39 HANDLE KeyHandle;
40 NTSTATUS Status;
41 KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
42 ULONG ResultLength;
43 UNICODE_STRING OptionKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\SafeBoot\\Option");
44 UNICODE_STRING AppCompatKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility");
45 UNICODE_STRING PolicyKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
46 UNICODE_STRING OptionValue = RTL_CONSTANT_STRING(L"OptionValue");
47 UNICODE_STRING DisableAppCompat = RTL_CONSTANT_STRING(L"DisableAppCompat");
48 UNICODE_STRING DisableEngine = RTL_CONSTANT_STRING(L"DisableEngine");
49 OBJECT_ATTRIBUTES OptionKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&OptionKey, OBJ_CASE_INSENSITIVE);
50 OBJECT_ATTRIBUTES AppCompatKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatKey, OBJ_CASE_INSENSITIVE);
51 OBJECT_ATTRIBUTES PolicyKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&PolicyKey, OBJ_CASE_INSENSITIVE);
52
53 /*
54 * This is a TROOLEAN, -1 means we haven't yet figured it out.
55 * 0 means shims are enabled, and 1 means shims are disabled!
56 */
57 if (g_ShimsEnabled == -1)
58 {
59 /* Open the safe mode key */
60 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &OptionKeyAttributes);
61 if (NT_SUCCESS(Status))
62 {
63 /* Check if this is safemode */
64 Status = NtQueryValueKey(KeyHandle,
65 &OptionValue,
66 KeyValuePartialInformation,
67 &KeyInfo,
68 sizeof(KeyInfo),
69 &ResultLength);
70 NtClose(KeyHandle);
71 if ((NT_SUCCESS(Status)) &&
72 (KeyInfo.Type == REG_DWORD) &&
73 (KeyInfo.DataLength == sizeof(ULONG)) &&
74 (KeyInfo.Data[0] == TRUE))
75 {
76 /* It is, so disable shims! */
77 g_ShimsEnabled = TRUE;
78 }
79 else
80 {
81 /* Open the app compatibility engine settings key */
82 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &AppCompatKeyAttributes);
83 if (NT_SUCCESS(Status))
84 {
85 /* Check if the app compat engine is turned off */
86 Status = NtQueryValueKey(KeyHandle,
87 &DisableAppCompat,
88 KeyValuePartialInformation,
89 &KeyInfo,
90 sizeof(KeyInfo),
91 &ResultLength);
92 NtClose(KeyHandle);
93 if ((NT_SUCCESS(Status)) &&
94 (KeyInfo.Type == REG_DWORD) &&
95 (KeyInfo.DataLength == sizeof(ULONG)) &&
96 (KeyInfo.Data[0] == TRUE))
97 {
98 /* It is, so disable shims! */
99 g_ShimsEnabled = TRUE;
100 }
101 else
102 {
103 /* Finally, open the app compatibility policy key */
104 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &PolicyKeyAttributes);
105 if (NT_SUCCESS(Status))
106 {
107 /* Check if the system policy disables app compat */
108 Status = NtQueryValueKey(KeyHandle,
109 &DisableEngine,
110 KeyValuePartialInformation,
111 &KeyInfo,
112 sizeof(KeyInfo),
113 &ResultLength);
114 NtClose(KeyHandle);
115 if ((NT_SUCCESS(Status)) &&
116 (KeyInfo.Type == REG_DWORD) &&
117 (KeyInfo.DataLength == sizeof(ULONG)) &&
118 (KeyInfo.Data[0] == TRUE))
119 {
120 /* It does, so disable shims! */
121 g_ShimsEnabled = TRUE;
122 }
123 else
124 {
125 /* No keys are set, so enable shims! */
126 g_ShimsEnabled = FALSE;
127 }
128 }
129 }
130 }
131 }
132 }
133 }
134
135 /* Return if shims are disabled or not ("Enabled == 1" means disabled!) */
136 return g_ShimsEnabled ? TRUE : FALSE;
137 }
138
139 /*
140 * @unimplemented
141 */
142 BOOL
143 WINAPI
144 BaseCheckAppcompatCache(IN PWCHAR ApplicationName,
145 IN HANDLE FileHandle,
146 IN PWCHAR Environment,
147 OUT PULONG Reason)
148 {
149 DPRINT("BaseCheckAppcompatCache is UNIMPLEMENTED\n");
150
151 if (Reason) *Reason = 0;
152
153 // We don't know this app.
154 return FALSE;
155 }
156
157 static
158 VOID
159 BaseInitApphelp(VOID)
160 {
161 WCHAR Buffer[MAX_PATH*2];
162 UNICODE_STRING DllPath = {0};
163 PVOID ApphelpAddress;
164 PVOID pApphelpCheckRunAppEx = NULL, pSdbPackAppCompatData = NULL;
165
166 RtlInitEmptyUnicodeString(&DllPath, Buffer, sizeof(Buffer));
167 RtlCopyUnicodeString(&DllPath, &BaseWindowsDirectory);
168 RtlAppendUnicodeToString(&DllPath, L"\\system32\\apphelp.dll");
169
170 if (NT_SUCCESS(LdrLoadDll(NULL, NULL, &DllPath, &ApphelpAddress)))
171 {
172 ANSI_STRING ProcName;
173
174 RtlInitAnsiString(&ProcName, "ApphelpCheckRunAppEx");
175 if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pApphelpCheckRunAppEx)))
176 pApphelpCheckRunAppEx = NULL;
177
178 RtlInitAnsiString(&ProcName, "SdbPackAppCompatData");
179 if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pSdbPackAppCompatData)))
180 pSdbPackAppCompatData = NULL;
181 }
182
183 if (InterlockedCompareExchangePointer(&g_pApphelpCheckRunAppEx, RtlEncodeSystemPointer(pApphelpCheckRunAppEx), NULL) == NULL)
184 {
185 g_pSdbPackAppCompatData = RtlEncodeSystemPointer(pSdbPackAppCompatData);
186 }
187 }
188
189 /*
190 *
191 */
192 BOOL
193 WINAPI
194 BaseCheckRunApp(IN HANDLE FileHandle,
195 IN PWCHAR ApplicationName,
196 IN PWCHAR Environment,
197 IN USHORT ExeType,
198 IN PULONG pReason,
199 IN PVOID* SdbQueryAppCompatData,
200 IN PULONG SdbQueryAppCompatDataSize,
201 IN PVOID* SxsData,
202 IN PULONG SxsDataSize,
203 OUT PULONG FusionFlags)
204 {
205 ULONG Reason = 0;
206 ULONG64 Flags1 = 0;
207 ULONG Flags2 = 0;
208 BOOL Continue, NeedCleanup = FALSE;
209 tApphelpCheckRunAppEx pApphelpCheckRunAppEx;
210 tSdbPackAppCompatData pSdbPackAppCompatData;
211 PVOID QueryResult = NULL;
212 ULONG QueryResultSize = 0;
213
214 if (!g_ApphelpInitialized)
215 {
216 BaseInitApphelp();
217 g_ApphelpInitialized = TRUE;
218 }
219
220 pApphelpCheckRunAppEx = RtlDecodeSystemPointer(g_pApphelpCheckRunAppEx);
221 pSdbPackAppCompatData = RtlDecodeSystemPointer(g_pSdbPackAppCompatData);
222
223 if (!pApphelpCheckRunAppEx || !pSdbPackAppCompatData)
224 return TRUE;
225
226 if (pReason)
227 Reason = *pReason;
228
229 Continue = pApphelpCheckRunAppEx(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, &Reason,
230 &QueryResult, &QueryResultSize, SxsData, SxsDataSize, FusionFlags, &Flags1, &Flags2);
231
232 if (pReason)
233 *pReason = Reason;
234
235 if (Continue)
236 {
237 if ((Reason & (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND)) == (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND))
238 {
239 if (!pSdbPackAppCompatData(NULL, QueryResult, SdbQueryAppCompatData, SdbQueryAppCompatDataSize))
240 {
241 DPRINT1("SdbPackAppCompatData returned a failure!\n");
242 NeedCleanup = TRUE;
243 }
244 }
245 else
246 {
247 NeedCleanup = TRUE;
248 }
249 }
250
251 if (QueryResult)
252 RtlFreeHeap(RtlGetProcessHeap(), 0, QueryResult);
253
254 if (NeedCleanup)
255 {
256 BasepFreeAppCompatData(*SdbQueryAppCompatData, *SxsData);
257 *SdbQueryAppCompatData = NULL;
258 if (SdbQueryAppCompatDataSize)
259 *SdbQueryAppCompatDataSize = 0;
260 *SxsData = NULL;
261 if (SxsDataSize)
262 *SxsDataSize = 0;
263 }
264
265 return Continue;
266 }
267
268 /*
269 * @implemented
270 */
271 NTSTATUS
272 WINAPI
273 BasepCheckBadapp(IN HANDLE FileHandle,
274 IN PWCHAR ApplicationName,
275 IN PWCHAR Environment,
276 IN USHORT ExeType,
277 IN PVOID* SdbQueryAppCompatData,
278 IN PULONG SdbQueryAppCompatDataSize,
279 IN PVOID* SxsData,
280 IN PULONG SxsDataSize,
281 OUT PULONG FusionFlags)
282 {
283 NTSTATUS Status = STATUS_SUCCESS;
284 ULONG Reason = 0;
285
286 /* Is shimming enabled by group policy? */
287 if (IsShimInfrastructureDisabled())
288 {
289 /* Nothing to worry about */
290 Status = STATUS_SUCCESS;
291 }
292 else
293 {
294 /* It is, check if we know about this app */
295 if (!BaseCheckAppcompatCache(ApplicationName,
296 FileHandle,
297 Environment,
298 &Reason))
299 {
300 if (!BaseCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
301 SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize, FusionFlags))
302 {
303 Status = STATUS_ACCESS_DENIED;
304 }
305 }
306 }
307
308 /* Return caller the status */
309 return Status;
310 }
311
312 /*
313 * @unimplemented
314 */
315 VOID
316 WINAPI
317 BaseDumpAppcompatCache(VOID)
318 {
319 STUB;
320 }
321
322 /*
323 * @unimplemented
324 */
325 VOID
326 WINAPI
327 BaseFlushAppcompatCache(VOID)
328 {
329 STUB;
330 }
331
332 /*
333 * @implemented
334 */
335 VOID
336 WINAPI
337 BasepFreeAppCompatData(IN PVOID AppCompatData,
338 IN PVOID AppCompatSxsData)
339 {
340 /* Free the input pointers if present */
341 if (AppCompatData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData);
342 if (AppCompatSxsData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatSxsData);
343 }
344
345 /*
346 * @unimplemented
347 */
348 VOID
349 WINAPI
350 BaseUpdateAppcompatCache(ULONG Unknown1,
351 ULONG Unknown2,
352 ULONG Unknown3)
353 {
354 STUB;
355 }
356
357 /*
358 * @unimplemented
359 */
360 NTSTATUS
361 WINAPI
362 BaseCleanupAppcompatCache(VOID)
363 {
364 STUB;
365 return STATUS_NOT_IMPLEMENTED;
366 }
367
368 /*
369 * @unimplemented
370 */
371 NTSTATUS
372 WINAPI
373 BaseCleanupAppcompatCacheSupport(PVOID pUnknown)
374 {
375 STUB;
376 return STATUS_NOT_IMPLEMENTED;
377 }
378
379 /*
380 * @unimplemented
381 */
382 BOOL
383 WINAPI
384 BaseInitAppcompatCache(VOID)
385 {
386 STUB;
387 return FALSE;
388 }
389
390 /*
391 * @unimplemented
392 */
393 BOOL
394 WINAPI
395 BaseInitAppcompatCacheSupport(VOID)
396 {
397 STUB;
398 return FALSE;
399 }
400
401 /*
402 * @unimplemented
403 */
404 PVOID
405 WINAPI
406 GetComPlusPackageInstallStatus(VOID)
407 {
408 STUB;
409 return NULL;
410 }
411
412 /*
413 * @unimplemented
414 */
415 BOOL
416 WINAPI
417 SetComPlusPackageInstallStatus(LPVOID lpInfo)
418 {
419 STUB;
420 return FALSE;
421 }
422
423 /*
424 * @unimplemented
425 */
426 VOID
427 WINAPI
428 SetTermsrvAppInstallMode(IN BOOL bInstallMode)
429 {
430 STUB;
431 }
432
433 /*
434 * @unimplemented
435 */
436 BOOL
437 WINAPI
438 TermsrvAppInstallMode(VOID)
439 {
440 STUB;
441 return FALSE;
442 }