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
38static PlatformShim platform_shim;
39
40extern "C" {
41
42static LibraryWrapper gdi32_dll;
43
44using PFN_GetSidSubAuthority = PDWORD(__stdcall *)(PSID pSid, DWORD nSubAuthority);
45static PFN_GetSidSubAuthority fpGetSidSubAuthority = GetSidSubAuthority;
46
47PDWORD __stdcall ShimGetSidSubAuthority(PSID, DWORD) { return &platform_shim.elevation_level; }
48
49static PFN_LoaderEnumAdapters2 fpEnumAdapters2 = nullptr;
50static PFN_LoaderQueryAdapterInfo fpQueryAdapterInfo = nullptr;
51
52NTSTATUS 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}
71NTSTATUS 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
121static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_List_SizeW)(PULONG pulLen, PCWSTR pszFilter, ULONG ulFlags) = CM_Get_Device_ID_List_SizeW;
122static CONFIGRET(WINAPI *REAL_CM_Get_Device_ID_ListW)(PCWSTR pszFilter, PZZWSTR Buffer, ULONG BufferLen, ULONG ulFlags) = CM_Get_Device_ID_ListW;
123static CONFIGRET(WINAPI *REAL_CM_Locate_DevNodeW)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags) =  CM_Locate_DevNodeW;
124static CONFIGRET(WINAPI *REAL_CM_Get_DevNode_Status)(PULONG pulStatus, PULONG pulProblemNumber, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_DevNode_Status;
125static CONFIGRET(WINAPI *REAL_CM_Get_Device_IDW)(DEVINST dnDevInst, PWSTR Buffer, ULONG BufferLen, ULONG ulFlags) =  CM_Get_Device_IDW;
126static CONFIGRET(WINAPI *REAL_CM_Get_Child)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) =  CM_Get_Child;
127static 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;
128static CONFIGRET(WINAPI *REAL_CM_Get_Sibling)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) = CM_Get_Sibling;
129// clang-format on
130
131CONFIGRET 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}
139CONFIGRET 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
150CONFIGRET WINAPI SHIM_CM_Locate_DevNodeW(PDEVINST, DEVINSTID_W, ULONG) { return CR_FAILURE; }
151// TODO
152CONFIGRET WINAPI SHIM_CM_Get_DevNode_Status(PULONG, PULONG, DEVINST, ULONG) { return CR_FAILURE; }
153// TODO
154CONFIGRET WINAPI SHIM_CM_Get_Device_IDW(DEVINST, PWSTR, ULONG, ULONG) { return CR_FAILURE; }
155// TODO
156CONFIGRET WINAPI SHIM_CM_Get_Child(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
157// TODO
158CONFIGRET WINAPI SHIM_CM_Get_DevNode_Registry_PropertyW(DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG) { return CR_FAILURE; }
159// TODO
160CONFIGRET WINAPI SHIM_CM_Get_Sibling(PDEVINST, DEVINST, ULONG) { return CR_FAILURE; }
161
162static LibraryWrapper dxgi_module;
163typedef HRESULT(APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory);
164
165PFN_CreateDXGIFactory1 RealCreateDXGIFactory1;
166
167HRESULT __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}
180ULONG __stdcall ShimIDXGIFactory1Release(IDXGIFactory1 *) { return S_OK; }
181ULONG __stdcall ShimIDXGIFactory6Release(IDXGIFactory6 *) { return S_OK; }
182ULONG __stdcall ShimRelease(IDXGIAdapter1 *) { return S_OK; }
183
184IDXGIAdapter1 *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
191HRESULT __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
204HRESULT __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
217HRESULT __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
233static 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
242static 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
252HRESULT __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
268using PFN_RegOpenKeyExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
269static PFN_RegOpenKeyExA fpRegOpenKeyExA = RegOpenKeyExA;
270using PFN_RegQueryValueExA = LSTATUS(__stdcall *)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
271                                                  LPDWORD lpcbData);
272static PFN_RegQueryValueExA fpRegQueryValueExA = RegQueryValueExA;
273using PFN_RegEnumValueA = LSTATUS(__stdcall *)(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName,
274                                               LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
275static PFN_RegEnumValueA fpRegEnumValueA = RegEnumValueA;
276
277using PFN_RegCloseKey = LSTATUS(__stdcall *)(HKEY hKey);
278static PFN_RegCloseKey fpRegCloseKey = RegCloseKey;
279
280LSTATUS __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}
294const 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}
302std::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}
312LSTATUS __stdcall ShimRegQueryValueExA(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD) {
313    // TODO:
314    return ERROR_SUCCESS;
315}
316LSTATUS __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}
339LSTATUS __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
350using PFN_GetPackagesByPackageFamily = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *);
351static PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = GetPackagesByPackageFamily;
352using PFN_GetPackagePathByFullName = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR);
353static PFN_GetPackagePathByFullName fpGetPackagePathByFullName = GetPackagePathByFullName;
354
355static constexpr wchar_t package_full_name[] = L"ThisIsARandomStringSinceTheNameDoesn'tMatter";
356LONG 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
383LONG 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
405void 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
461void 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
485BOOL 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}
497FRAMEWORK_EXPORT PlatformShim *get_platform_shim(std::vector<fs::FolderManager> *folders) {
498    platform_shim = PlatformShim(folders);
499    return &platform_shim;
500}
501}
502