2 * Copyright 2011 André Hentschel
3 * Copyright 2013 Mislav Blažević
4 * Copyright 2015-2017 Mark Jansen
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.
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.
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
21 #define WIN32_NO_STATUS
27 #include "ndk/rtlfuncs.h"
28 #include "ndk/kdtypes.h"
32 #define DPFLTR_APPCOMPAT_ID 123
35 #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
38 ULONG g_ShimDebugLevel
= 0xffffffff;
41 void ApphelppInitDebugLevel(void)
43 static const UNICODE_STRING DebugKey
= RTL_CONSTANT_STRING(L
"SHIM_DEBUG_LEVEL");
44 UNICODE_STRING DebugValue
;
46 ULONG NewLevel
= SHIM_ERR
;
49 RtlInitEmptyUnicodeString(&DebugValue
, Buffer
, sizeof(Buffer
));
51 Status
= RtlQueryEnvironmentVariable_U(NULL
, &DebugKey
, &DebugValue
);
53 if (NT_SUCCESS(Status
))
55 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&DebugValue
, 10, &NewLevel
)))
58 g_ShimDebugLevel
= NewLevel
;
62 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
67 case DLL_WINE_PREATTACH
:
68 return FALSE
; /* prefer native version */
70 case DLL_PROCESS_ATTACH
:
72 DisableThreadLibraryCalls( hinst
);
75 case DLL_PROCESS_DETACH
:
82 BOOL WINAPI
ApphelpCheckInstallShieldPackage(void* ptr
, LPCWSTR path
)
84 SHIM_WARN("stub: ptr=%p, path='%S'\r\n", ptr
, path
);
89 BOOL WINAPI
ApphelpCheckShellObject(REFCLSID ObjectCLSID
, BOOL bShimIfNecessary
, ULONGLONG
*pullFlags
)
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
);
103 * Outputs diagnostic info.
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.
111 * @return Success: TRUE Failure: FALSE.
113 BOOL WINAPIV
ShimDbgPrint(SHIM_LOG_LEVEL Level
, PCSTR FunctionName
, PCSTR Format
, ...)
117 char* Current
= Buffer
;
118 const char* LevelStr
;
119 size_t Length
= sizeof(Buffer
);
121 if (g_ShimDebugLevel
== 0xffffffff)
122 ApphelppInitDebugLevel();
124 if (Level
> g_ShimDebugLevel
)
131 Level
= DPFLTR_MASK
| (1 << DPFLTR_ERROR_LEVEL
);
135 Level
= DPFLTR_MASK
| (1 << DPFLTR_WARNING_LEVEL
);
139 Level
= DPFLTR_MASK
| (1 << DPFLTR_INFO_LEVEL
);
143 Level
= DPFLTR_MASK
| (1 << DPFLTR_INFO_LEVEL
);
146 StringCchPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, "[%s][%-20s] ", LevelStr
, FunctionName
);
148 va_start(ArgList
, Format
);
149 StringCchVPrintfExA(Current
, Length
, &Current
, &Length
, STRSAFE_NULL_ON_FAILURE
, Format
, ArgList
);
152 #if defined(APPCOMPAT_USE_DBGPRINTEX) && APPCOMPAT_USE_DBGPRINTEX
153 return NT_SUCCESS(DbgPrintEx(DPFLTR_APPCOMPAT_ID
, Level
, "%s", Buffer
));
155 OutputDebugStringA(Buffer
);
161 #define APPHELP_DONTWRITE_REASON 2
162 #define APPHELP_CLEARBITS 0x100 /* TODO: Investigate */
163 #define APPHELP_IGNORE_ENVIRONMENT 0x400
165 #define APPHELP_VALID_RESULT 0x10000
166 #define APPHELP_RESULT_NOTFOUND 0x20000
167 #define APPHELP_RESULT_FOUND 0x40000
170 * Lookup Shims / Fixes for the specified application
172 * @param [in] FileHandle Handle to the file to check.
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
187 * @return TRUE if the application is allowed to run.
191 ApphelpCheckRunAppEx(
192 _In_ HANDLE FileHandle
,
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
)
207 SDBQUERYRESULT
* result
= NULL
;
224 dwFlags
&= ~APPHELP_CLEARBITS
;
226 *SdbQueryAppCompatData
= result
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SDBQUERYRESULT
));
227 if (SdbQueryAppCompatDataSize
)
228 *SdbQueryAppCompatDataSize
= sizeof(*result
);
231 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
235 DWORD MatchingExeFlags
= 0;
237 if (dwFlags
& APPHELP_IGNORE_ENVIRONMENT
)
238 MatchingExeFlags
|= SDBGMEF_IGNORE_ENVIRONMENT
;
240 FoundMatch
= SdbGetMatchingExe(hsdb
, ApplicationName
, NULL
, Environment
, MatchingExeFlags
, result
);
241 if (FileHandle
!= INVALID_HANDLE_VALUE
)
243 dwFlags
|= APPHELP_VALID_RESULT
;
244 dwFlags
|= (FoundMatch
? APPHELP_RESULT_FOUND
: APPHELP_RESULT_NOTFOUND
);
247 SdbReleaseDatabase(hsdb
);
250 if (Reason
&& !(dwFlags
& APPHELP_DONTWRITE_REASON
))
254 /* We should _ALWAYS_ return TRUE here, unless we want to block an application from starting! */