1 /*
2  * Copyright (c) 2021 The Khronos Group Inc.
3  * Copyright (c) 2021 Valve Corporation
4  * Copyright (c) 2021 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Charles Giessen <charles@lunarg.com>
26  */
27 
28 // This needs to be defined first, or else we'll get redefinitions on NTSTATUS values
29 #if defined(_WIN32)
30 #define UMDF_USING_NTSTATUS
31 #include <ntstatus.h>
32 #endif
33 
34 #include "shim.h"
35 
36 #include "detours.h"
37 
38 static PlatformShim platform_shim;
39 
40 extern "C" {
41 
42 static LibraryWrapper gdi32_dll;
43 
44 using PFN_GetSidSubAuthority = PDWORD(__stdcall *)(PSID pSid, DWORD nSubAuthority);
45 static PFN_GetSidSubAuthority fpGetSidSubAuthority = GetSidSubAuthority;
46 
ShimGetSidSubAuthority(PSID, DWORD)47 PDWORD __stdcall ShimGetSidSubAuthority(PSID, DWORD) { return &platform_shim.elevation_level; }
48 
49 static PFN_LoaderEnumAdapters2 fpEnumAdapters2 = nullptr;
50 static PFN_LoaderQueryAdapterInfo fpQueryAdapterInfo = nullptr;
51 
ShimEnumAdapters2(LoaderEnumAdapters2 *adapters)52 NTSTATUS APIENTRY ShimEnumAdapters2(LoaderEnumAdapters2 *adapters) {
53     if (adapters == nullptr) {
54         return STATUS_INVALID_PARAMETER;
55     }
56     if (platform_shim.d3dkmt_adapters.size() == 0) {
57         if (adapters->adapters != nullptr) adapters->adapter_count = 0;
58         return STATUS_SUCCESS;
59     }
60     if (adapters->adapters != nullptr) {
61         for (size_t i = 0; i < platform_shim.d3dkmt_adapters.size(); i++) {
62             adapters->adapters[i].handle = platform_shim.d3dkmt_adapters[i].hAdapter;
63             adapters->adapters[i].luid = platform_shim.d3dkmt_adapters[i].adapter_luid;
64         }
65         adapters->adapter_count = static_cast<ULONG>(platform_shim.d3dkmt_adapters.size());
66     } else {
67         adapters->adapter_count = static_cast<ULONG>(platform_shim.d3dkmt_adapters.size());
68     }
69     return STATUS_SUCCESS;
70 }
ShimQueryAdapterInfo(const LoaderQueryAdapterInfo *query_info)71 NTSTATUS APIENTRY ShimQueryAdapterInfo(const LoaderQueryAdapterInfo *query_info) {
72     if (query_info == nullptr || query_info->private_data == nullptr) {
73         return STATUS_INVALID_PARAMETER;
74     }
75     auto handle = query_info->handle;
76     auto it = std::find_if(platform_shim.d3dkmt_adapters.begin(), platform_shim.d3dkmt_adapters.end(),
77                            [handle](D3DKMT_Adapter const &adapter) { return handle == adapter.hAdapter; });
78     if (it == platform_shim.d3dkmt_adapters.end()) {
79         return STATUS_INVALID_PARAMETER;
80     }
81     auto &adapter = *it;
82     auto *reg_info = reinterpret_cast<LoaderQueryRegistryInfo *>(query_info->private_data);
83 
84     std::vector<std::wstring> *paths = nullptr;
85     if (wcsstr(reg_info->value_name, L"DriverName") != nullptr) {  // looking for drivers
86         paths = &adapter.driver_paths;
87     } else if (wcsstr(reg_info->value_name, L"ImplicitLayers") != nullptr) {  // looking for implicit layers
88         paths = &adapter.implicit_layer_paths;
89     } else if (wcsstr(reg_info->value_name, L"ExplicitLayers") != nullptr) {  // looking for explicit layers
90         paths = &adapter.explicit_layer_paths;
91     }
92 
93     reg_info->status = LOADER_QUERY_REGISTRY_STATUS_SUCCESS;
94     if (reg_info->output_value_size == 0) {
95         ULONG size = 2;  // final null terminator
96         for (auto const &path : *paths) size = static_cast<ULONG>(path.length() * sizeof(wchar_t));
97         // size in bytes, so multiply path size by two and add 2 for the null terminator
98         reg_info->output_value_size = size;
99         if (size != 2) {
100             // only want to write data if there is path data to write
101             reg_info->status = LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW;
102         }
103     } else if (reg_info->output_value_size > 2) {
104         size_t index = 0;
105         for (auto const &path : *paths) {
106             for (auto w : path) {
107                 reg_info->output_string[index++] = w;
108             }
109             reg_info->output_string[index++] = L'\0';
110         }
111         // make sure there is a null terminator
112         reg_info->output_string[index++] = L'\0';
113 
114         reg_info->status = LOADER_QUERY_REGISTRY_STATUS_SUCCESS;
115     }
116 
117     return STATUS_SUCCESS;
118 }
119 
120 // clang-format off
121 static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_List_SizeW)(PULONG pulLen, PCWSTR pszFilter, ULONG ulFlags) = CM_Get_Device_ID_List_SizeW;
122 static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_ListW)(PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen, ULONG ulFlags) = CM_Get_Device_ID_ListW;
123 static CONFIGRET(WINAPI *REAL_CM_Locate_DevNodeW)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags) =  CM_Locate_DevNodeW;
124 static CONFIGRET(WINAPI *REAL_CM_Get_DevNode_Status)(PULONG pulStatus, PULONG pulProblemNumber, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_DevNode_Status;
125 static CONFIGRET(WINAPI *REAL_CM_Get_Device_IDW)(DEVINST dnDevInst, PWSTR Buffer, ULONG BufferLen, ULONG ulFlags) =  CM_Get_Device_IDW;
126 static CONFIGRET(WINAPI *REAL_CM_Get_Child)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_Child;
127 static CONFIGRET(WINAPI *REAL_CM_Get_DevNode_Registry_PropertyW)(DEVINST dnDevInst, ULONG ulProperty, PULONG pulRegDataType, PVOID Buffer, PULONG pulLength, ULONG ulFlags) =  CM_Get_DevNode_Registry_PropertyW;
128 static CONFIGRET(WINAPI *REAL_CM_Get_Sibling)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) = CM_Get_Sibling;
129 // clang-format on
130 
SHIM_CM_Get_Device_ID_List_SizeW(PULONG pulLen, [[maybe_unused]] PCWSTR pszFilter, [[maybe_unused]] ULONG ulFlags)131 CONFIGRET WINAPI SHIM_CM_Get_Device_ID_List_SizeW(PULONG pulLen, [[maybe_unused]] PCWSTR pszFilter,
132                                                   [[maybe_unused]] ULONG ulFlags) {
133     if (pulLen == nullptr) {
134         return CR_INVALID_POINTER;
135     }
136     *pulLen = static_cast<ULONG>(platform_shim.CM_device_ID_list.size());
137     return CR_SUCCESS;
138 }
SHIM_CM_Get_Device_ID_ListW([[maybe_unused]] PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen, [[maybe_unused]] ULONG ulFlags)139 CONFIGRET WINAPI SHIM_CM_Get_Device_ID_ListW([[maybe_unused]] PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen,
140                                              [[maybe_unused]] ULONG ulFlags) {
141     if (Buffer != NULL) {
142         if (BufferLen < platform_shim.CM_device_ID_list.size()) return CR_BUFFER_SMALL;
143         for (size_t i = 0; i < BufferLen; i++) {
144             Buffer[i] = platform_shim.CM_device_ID_list[i];
145         }
146     }
147     return CR_SUCCESS;
148 }
149 // TODO
SHIM_CM_Locate_DevNodeW(PDEVINST, DEVINSTID_W, ULONG)150 CONFIGRET WINAPI SHIM_CM_Locate_DevNodeW(PDEVINST, DEVINSTID_W, ULONG) { return CR_FAILURE; }
151 // TODO
SHIM_CM_Get_DevNode_Status(PULONG, PULONG, DEVINST, ULONG)152 CONFIGRET WINAPI SHIM_CM_Get_DevNode_Status(PULONG, PULONG, DEVINST, ULONG) { return CR_FAILURE; }
153 // TODO
SHIM_CM_Get_Device_IDW(DEVINST, PWSTR, ULONG, ULONG)154 CONFIGRET WINAPI SHIM_CM_Get_Device_IDW(DEVINST, PWSTR, ULONG, ULONG) { return CR_FAILURE; }
155 // TODO
SHIM_CM_Get_Child(PDEVINST, DEVINST, ULONG)156 CONFIGRET WINAPI SHIM_CM_Get_Child(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
157 // TODO
SHIM_CM_Get_DevNode_Registry_PropertyW(DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG)158 CONFIGRET WINAPI SHIM_CM_Get_DevNode_Registry_PropertyW(DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG) { return CR_FAILURE; }
159 // TODO
SHIM_CM_Get_Sibling(PDEVINST, DEVINST, ULONG)160 CONFIGRET WINAPI SHIM_CM_Get_Sibling(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
161 
162 static LibraryWrapper dxgi_module;
163 typedef HRESULT(APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory);
164 
165 PFN_CreateDXGIFactory1 RealCreateDXGIFactory1;
166 
ShimGetDesc1(IDXGIAdapter1 *pAdapter, _Out_ DXGI_ADAPTER_DESC1 *pDesc)167 HRESULT __stdcall ShimGetDesc1(IDXGIAdapter1 *pAdapter,
168                                /* [annotation][out] */
169                                _Out_ DXGI_ADAPTER_DESC1 *pDesc) {
170     if (pAdapter == nullptr || pDesc == nullptr) return DXGI_ERROR_INVALID_CALL;
171 
172     for (const auto &[index, adapter] : platform_shim.dxgi_adapters) {
173         if (&adapter.adapter_instance == pAdapter) {
174             *pDesc = adapter.desc1;
175             return S_OK;
176         }
177     }
178     return DXGI_ERROR_INVALID_CALL;
179 }
ShimIDXGIFactory1Release(IDXGIFactory1 *)180 ULONG __stdcall ShimIDXGIFactory1Release(IDXGIFactory1 *) { return S_OK; }
ShimIDXGIFactory6Release(IDXGIFactory6 *)181 ULONG __stdcall ShimIDXGIFactory6Release(IDXGIFactory6 *) { return S_OK; }
ShimRelease(IDXGIAdapter1 *)182 ULONG __stdcall ShimRelease(IDXGIAdapter1 *) { return S_OK; }
183 
setup_and_get_IDXGIAdapter1(DXGIAdapter &adapter)184 IDXGIAdapter1 *setup_and_get_IDXGIAdapter1(DXGIAdapter &adapter) {
185     adapter.adapter_vtbl_instance.GetDesc1 = ShimGetDesc1;
186     adapter.adapter_vtbl_instance.Release = ShimRelease;
187     adapter.adapter_instance.lpVtbl = &adapter.adapter_vtbl_instance;
188     return &adapter.adapter_instance;
189 }
190 
ShimEnumAdapters1_1([[maybe_unused]] IDXGIFactory1 *This, UINT Adapter, _COM_Outptr_ IDXGIAdapter1 **ppAdapter)191 HRESULT __stdcall ShimEnumAdapters1_1([[maybe_unused]] IDXGIFactory1 *This,
192                                       /* [in] */ UINT Adapter,
193                                       /* [annotation][out] */
194                                       _COM_Outptr_ IDXGIAdapter1 **ppAdapter) {
195     if (Adapter >= platform_shim.dxgi_adapters.size()) {
196         return DXGI_ERROR_INVALID_CALL;
197     }
198     if (ppAdapter != nullptr) {
199         *ppAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
200     }
201     return S_OK;
202 }
203 
ShimEnumAdapters1_6([[maybe_unused]] IDXGIFactory6 *This, UINT Adapter, _COM_Outptr_ IDXGIAdapter1 **ppAdapter)204 HRESULT __stdcall ShimEnumAdapters1_6([[maybe_unused]] IDXGIFactory6 *This,
205                                       /* [in] */ UINT Adapter,
206                                       /* [annotation][out] */
207                                       _COM_Outptr_ IDXGIAdapter1 **ppAdapter) {
208     if (Adapter >= platform_shim.dxgi_adapters.size()) {
209         return DXGI_ERROR_INVALID_CALL;
210     }
211     if (ppAdapter != nullptr) {
212         *ppAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
213     }
214     return S_OK;
215 }
216 
ShimEnumAdapterByGpuPreference([[maybe_unused]] IDXGIFactory6 *This, _In_ UINT Adapter, [[maybe_unused]] _In_ DXGI_GPU_PREFERENCE GpuPreference, [[maybe_unused]] _In_ REFIID riid, _COM_Outptr_ void **ppvAdapter)217 HRESULT __stdcall ShimEnumAdapterByGpuPreference([[maybe_unused]] IDXGIFactory6 *This, _In_ UINT Adapter,
218                                                  [[maybe_unused]] _In_ DXGI_GPU_PREFERENCE GpuPreference,
219                                                  [[maybe_unused]] _In_ REFIID riid, _COM_Outptr_ void **ppvAdapter) {
220     if (Adapter >= platform_shim.dxgi_adapters.size()) {
221         return DXGI_ERROR_NOT_FOUND;
222     }
223     // loader always uses DXGI_GPU_PREFERENCE_UNSPECIFIED
224     // Update the shim if this isn't the case
225     assert(GpuPreference == DXGI_GPU_PREFERENCE::DXGI_GPU_PREFERENCE_UNSPECIFIED &&
226            "Test shim assumes the GpuPreference is unspecified.");
227     if (ppvAdapter != nullptr) {
228         *ppvAdapter = setup_and_get_IDXGIAdapter1(platform_shim.dxgi_adapters.at(Adapter));
229     }
230     return S_OK;
231 }
232 
get_IDXGIFactory1()233 static IDXGIFactory1 *get_IDXGIFactory1() {
234     static IDXGIFactory1Vtbl vtbl{};
235     vtbl.EnumAdapters1 = ShimEnumAdapters1_1;
236     vtbl.Release = ShimIDXGIFactory1Release;
237     static IDXGIFactory1 factory{};
238     factory.lpVtbl = &vtbl;
239     return &factory;
240 }
241 
get_IDXGIFactory6()242 static IDXGIFactory6 *get_IDXGIFactory6() {
243     static IDXGIFactory6Vtbl vtbl{};
244     vtbl.EnumAdapters1 = ShimEnumAdapters1_6;
245     vtbl.EnumAdapterByGpuPreference = ShimEnumAdapterByGpuPreference;
246     vtbl.Release = ShimIDXGIFactory6Release;
247     static IDXGIFactory6 factory{};
248     factory.lpVtbl = &vtbl;
249     return &factory;
250 }
251 
ShimCreateDXGIFactory1(REFIID riid, void **ppFactory)252 HRESULT __stdcall ShimCreateDXGIFactory1(REFIID riid, void **ppFactory) {
253     if (riid == IID_IDXGIFactory1) {
254         auto *factory = get_IDXGIFactory1();
255         *ppFactory = factory;
256         return S_OK;
257     }
258     if (riid == IID_IDXGIFactory6) {
259         auto *factory = get_IDXGIFactory6();
260         *ppFactory = factory;
261         return S_OK;
262     }
263     assert(false && "new riid, update shim code to handle");
264     return S_FALSE;
265 }
266 
267 // Windows Registry shims
268 using PFN_RegOpenKeyExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
269 static PFN_RegOpenKeyExA fpRegOpenKeyExA = RegOpenKeyExA;
270 using PFN_RegQueryValueExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
271                                                   LPDWORD lpcbData);
272 static PFN_RegQueryValueExA fpRegQueryValueExA = RegQueryValueExA;
273 using PFN_RegEnumValueA = LSTATUS(__stdcall *)(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName,
274                                                LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
275 static PFN_RegEnumValueA fpRegEnumValueA = RegEnumValueA;
276 
277 using PFN_RegCloseKey = LSTATUS(__stdcall *)(HKEY hKey);
278 static PFN_RegCloseKey fpRegCloseKey = RegCloseKey;
279 
ShimRegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, [[maybe_unused]] DWORD ulOptions, [[maybe_unused]] REGSAM samDesired, PHKEY phkResult)280 LSTATUS __stdcall ShimRegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, [[maybe_unused]] DWORD ulOptions,
281                                     [[maybe_unused]] REGSAM samDesired, PHKEY phkResult) {
282     if (HKEY_LOCAL_MACHINE != hKey && HKEY_CURRENT_USER != hKey) return ERROR_BADKEY;
283     std::string hive = "";
284     if (HKEY_LOCAL_MACHINE == hKey)
285         hive = "HKEY_LOCAL_MACHINE";
286     else if (HKEY_CURRENT_USER == hKey)
287         hive = "HKEY_CURRENT_USER";
288     if (hive == "") return ERROR_ACCESS_DENIED;
289 
290     platform_shim.created_keys.emplace_back(platform_shim.created_key_count++, hive + "\\" + lpSubKey);
291     *phkResult = platform_shim.created_keys.back().get();
292     return 0;
293 }
get_path_of_created_key(HKEY hKey)294 const std::string *get_path_of_created_key(HKEY hKey) {
295     for (const auto &key : platform_shim.created_keys) {
296         if (key.key == hKey) {
297             return &key.path;
298         }
299     }
300     return nullptr;
301 }
get_registry_vector(std::string const &path)302 std::vector<RegistryEntry> *get_registry_vector(std::string const &path) {
303     if (path == "HKEY_LOCAL_MACHINE\\" VK_DRIVERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_drivers;
304     if (path == "HKEY_LOCAL_MACHINE\\" VK_ELAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_explicit_layers;
305     if (path == "HKEY_LOCAL_MACHINE\\" VK_ILAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_implicit_layers;
306     if (path == "HKEY_CURRENT_USER\\" VK_ELAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_explicit_layers;
307     if (path == "HKEY_CURRENT_USER\\" VK_ILAYERS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_implicit_layers;
308     if (path == "HKEY_LOCAL_MACHINE\\" VK_SETTINGS_INFO_REGISTRY_LOC) return &platform_shim.hkey_local_machine_settings;
309     if (path == "HKEY_CURRENT_USER\\" VK_SETTINGS_INFO_REGISTRY_LOC) return &platform_shim.hkey_current_user_settings;
310     return nullptr;
311 }
ShimRegQueryValueExA(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)312 LSTATUS __stdcall ShimRegQueryValueExA(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD) {
313     // TODO:
314     return ERROR_SUCCESS;
315 }
ShimRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName, [[maybe_unused]] LPDWORD lpReserved, [[maybe_unused]] LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)316 LSTATUS __stdcall ShimRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName,
317                                     [[maybe_unused]] LPDWORD lpReserved, [[maybe_unused]] LPDWORD lpType, LPBYTE lpData,
318                                     LPDWORD lpcbData) {
319     const std::string *path = get_path_of_created_key(hKey);
320     if (path == nullptr) return ERROR_NO_MORE_ITEMS;
321 
322     const auto *location_ptr = get_registry_vector(*path);
323     if (location_ptr == nullptr) return ERROR_NO_MORE_ITEMS;
324     const auto &location = *location_ptr;
325     if (dwIndex >= location.size()) return ERROR_NO_MORE_ITEMS;
326 
327     if (*lpcchValueName < location[dwIndex].name.size()) return ERROR_NO_MORE_ITEMS;
328     for (size_t i = 0; i < location[dwIndex].name.size(); i++) {
329         lpValueName[i] = location[dwIndex].name[i];
330     }
331     lpValueName[location[dwIndex].name.size()] = '\0';
332     *lpcchValueName = static_cast<DWORD>(location[dwIndex].name.size() + 1);
333     if (*lpcbData < sizeof(DWORD)) return ERROR_NO_MORE_ITEMS;
334     DWORD *lpcbData_dword = reinterpret_cast<DWORD *>(lpData);
335     *lpcbData_dword = location[dwIndex].value;
336     *lpcbData = sizeof(DWORD);
337     return ERROR_SUCCESS;
338 }
ShimRegCloseKey(HKEY hKey)339 LSTATUS __stdcall ShimRegCloseKey(HKEY hKey) {
340     for (size_t i = 0; i < platform_shim.created_keys.size(); i++) {
341         if (platform_shim.created_keys[i].get() == hKey) {
342             platform_shim.created_keys.erase(platform_shim.created_keys.begin() + i);
343             return ERROR_SUCCESS;
344         }
345     }
346     return ERROR_SUCCESS;
347 }
348 
349 // Windows app package shims
350 using PFN_GetPackagesByPackageFamily = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *);
351 static PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = GetPackagesByPackageFamily;
352 using PFN_GetPackagePathByFullName = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR);
353 static PFN_GetPackagePathByFullName fpGetPackagePathByFullName = GetPackagePathByFullName;
354 
355 static constexpr wchar_t package_full_name[] = L"ThisIsARandomStringSinceTheNameDoesn'tMatter";
ShimGetPackagesByPackageFamily(_In_ PCWSTR packageFamilyName, _Inout_ UINT32 *count, _Out_writes_opt_(*count) PWSTR *packageFullNames, _Inout_ UINT32 *bufferLength, _Out_writes_opt_(*bufferLength) WCHAR *buffer)356 LONG WINAPI ShimGetPackagesByPackageFamily(_In_ PCWSTR packageFamilyName, _Inout_ UINT32 *count,
357                                            _Out_writes_opt_(*count) PWSTR *packageFullNames, _Inout_ UINT32 *bufferLength,
358                                            _Out_writes_opt_(*bufferLength) WCHAR *buffer) {
359     if (!packageFamilyName || !count || !bufferLength) return ERROR_INVALID_PARAMETER;
360     if (!platform_shim.app_package_path.empty() && wcscmp(packageFamilyName, L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe") == 0) {
361         if (*count > 0 && !packageFullNames) return ERROR_INVALID_PARAMETER;
362         if (*bufferLength > 0 && !buffer) return ERROR_INVALID_PARAMETER;
363         if (*count > 1) return ERROR_INVALID_PARAMETER;
364         bool too_small = *count < 1 || *bufferLength < ARRAYSIZE(package_full_name);
365         *count = 1;
366         *bufferLength = ARRAYSIZE(package_full_name);
367         if (too_small) return ERROR_INSUFFICIENT_BUFFER;
368 
369         for (size_t i = 0; i < sizeof(package_full_name) / sizeof(wchar_t); i++) {
370             if (i >= *bufferLength) {
371                 break;
372             }
373             buffer[i] = package_full_name[i];
374         }
375         *packageFullNames = buffer;
376         return 0;
377     }
378     *count = 0;
379     *bufferLength = 0;
380     return 0;
381 }
382 
383 LONG WINAPI ShimGetPackagePathByFullName(_In_ PCWSTR packageFullName, _Inout_ UINT32 *pathLength,
384                                          _Out_writes_opt_(*pathLength) PWSTR path) {
385     if (!packageFullName || !pathLength) return ERROR_INVALID_PARAMETER;
386     if (*pathLength > 0 && !path) return ERROR_INVALID_PARAMETER;
387     if (wcscmp(packageFullName, package_full_name) != 0) {
388         *pathLength = 0;
389         return 0;
390     }
391     if (*pathLength < platform_shim.app_package_path.size() + 1) {
392         *pathLength = static_cast<UINT32>(platform_shim.app_package_path.size() + 1);
393         return ERROR_INSUFFICIENT_BUFFER;
394     }
395     for (size_t i = 0; i < platform_shim.app_package_path.length(); i++) {
396         if (i >= *pathLength) {
397             break;
398         }
399         path[i] = platform_shim.app_package_path.c_str()[i];
400     }
401     return 0;
402 }
403 
404 // Initialization
405 void WINAPI DetourFunctions() {
406     if (!gdi32_dll) {
407         gdi32_dll = LibraryWrapper("gdi32.dll");
408         fpEnumAdapters2 = gdi32_dll.get_symbol("D3DKMTEnumAdapters2");
409         if (fpEnumAdapters2 == nullptr) {
410             std::cerr << "Failed to load D3DKMTEnumAdapters2\n";
411             return;
412         }
413         fpQueryAdapterInfo = gdi32_dll.get_symbol("D3DKMTQueryAdapterInfo");
414         if (fpQueryAdapterInfo == nullptr) {
415             std::cerr << "Failed to load D3DKMTQueryAdapterInfo\n";
416             return;
417         }
418     }
419     if (!dxgi_module) {
420         TCHAR systemPath[MAX_PATH] = "";
421         GetSystemDirectory(systemPath, MAX_PATH);
422         StringCchCat(systemPath, MAX_PATH, TEXT("\\dxgi.dll"));
423         dxgi_module = LibraryWrapper(systemPath);
424         RealCreateDXGIFactory1 = dxgi_module.get_symbol("CreateDXGIFactory1");
425         if (RealCreateDXGIFactory1 == nullptr) {
426             std::cerr << "Failed to load CreateDXGIFactory1\n";
427         }
428     }
429 
430     DetourRestoreAfterWith();
431 
432     DetourTransactionBegin();
433     DetourUpdateThread(GetCurrentThread());
434     DetourAttach(&(PVOID &)fpGetSidSubAuthority, (PVOID)ShimGetSidSubAuthority);
435     DetourAttach(&(PVOID &)fpEnumAdapters2, (PVOID)ShimEnumAdapters2);
436     DetourAttach(&(PVOID &)fpQueryAdapterInfo, (PVOID)ShimQueryAdapterInfo);
437     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_List_SizeW, (PVOID)SHIM_CM_Get_Device_ID_List_SizeW);
438     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
439     DetourAttach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
440     DetourAttach(&(PVOID &)REAL_CM_Locate_DevNodeW, (PVOID)SHIM_CM_Locate_DevNodeW);
441     DetourAttach(&(PVOID &)REAL_CM_Get_DevNode_Status, (PVOID)SHIM_CM_Get_DevNode_Status);
442     DetourAttach(&(PVOID &)REAL_CM_Get_Device_IDW, (PVOID)SHIM_CM_Get_Device_IDW);
443     DetourAttach(&(PVOID &)REAL_CM_Get_Child, (PVOID)SHIM_CM_Get_Child);
444     DetourAttach(&(PVOID &)REAL_CM_Get_DevNode_Registry_PropertyW, (PVOID)SHIM_CM_Get_DevNode_Registry_PropertyW);
445     DetourAttach(&(PVOID &)REAL_CM_Get_Sibling, (PVOID)SHIM_CM_Get_Sibling);
446     DetourAttach(&(PVOID &)RealCreateDXGIFactory1, (PVOID)ShimCreateDXGIFactory1);
447     DetourAttach(&(PVOID &)fpRegOpenKeyExA, (PVOID)ShimRegOpenKeyExA);
448     DetourAttach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA);
449     DetourAttach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA);
450     DetourAttach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey);
451     DetourAttach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily);
452     DetourAttach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName);
453     LONG error = DetourTransactionCommit();
454 
455     if (error != NO_ERROR) {
456         std::cerr << "simple" << DETOURS_STRINGIFY(DETOURS_BITS) << ".dll:"
457                   << " Error detouring function(): " << error << "\n";
458     }
459 }
460 
461 void DetachFunctions() {
462     DetourTransactionBegin();
463     DetourUpdateThread(GetCurrentThread());
464     DetourDetach(&(PVOID &)fpGetSidSubAuthority, (PVOID)ShimGetSidSubAuthority);
465     DetourDetach(&(PVOID &)fpEnumAdapters2, (PVOID)ShimEnumAdapters2);
466     DetourDetach(&(PVOID &)fpQueryAdapterInfo, (PVOID)ShimQueryAdapterInfo);
467     DetourDetach(&(PVOID &)REAL_CM_Get_Device_ID_List_SizeW, (PVOID)SHIM_CM_Get_Device_ID_List_SizeW);
468     DetourDetach(&(PVOID &)REAL_CM_Get_Device_ID_ListW, (PVOID)SHIM_CM_Get_Device_ID_ListW);
469     DetourDetach(&(PVOID &)REAL_CM_Locate_DevNodeW, (PVOID)SHIM_CM_Locate_DevNodeW);
470     DetourDetach(&(PVOID &)REAL_CM_Get_DevNode_Status, (PVOID)SHIM_CM_Get_DevNode_Status);
471     DetourDetach(&(PVOID &)REAL_CM_Get_Device_IDW, (PVOID)SHIM_CM_Get_Device_IDW);
472     DetourDetach(&(PVOID &)REAL_CM_Get_Child, (PVOID)SHIM_CM_Get_Child);
473     DetourDetach(&(PVOID &)REAL_CM_Get_DevNode_Registry_PropertyW, (PVOID)SHIM_CM_Get_DevNode_Registry_PropertyW);
474     DetourDetach(&(PVOID &)REAL_CM_Get_Sibling, (PVOID)SHIM_CM_Get_Sibling);
475     DetourDetach(&(PVOID &)RealCreateDXGIFactory1, (PVOID)ShimCreateDXGIFactory1);
476     DetourDetach(&(PVOID &)fpRegOpenKeyExA, (PVOID)ShimRegOpenKeyExA);
477     DetourDetach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA);
478     DetourDetach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA);
479     DetourDetach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey);
480     DetourDetach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily);
481     DetourDetach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName);
482     DetourTransactionCommit();
483 }
484 
485 BOOL WINAPI DllMain([[maybe_unused]] HINSTANCE hinst, DWORD dwReason, [[maybe_unused]] LPVOID reserved) {
486     if (DetourIsHelperProcess()) {
487         return TRUE;
488     }
489 
490     if (dwReason == DLL_PROCESS_ATTACH) {
491         DetourFunctions();
492     } else if (dwReason == DLL_PROCESS_DETACH) {
493         DetachFunctions();
494     }
495     return TRUE;
496 }
497 FRAMEWORK_EXPORT PlatformShim *get_platform_shim(std::vector<fs::FolderManager> *folders) {
498     platform_shim = PlatformShim(folders);
499     return &platform_shim;
500 }
501 }
502