Skip to content

Commit

Permalink
Fix thread suspension, fix debug v. release mode,
Browse files Browse the repository at this point in the history
Split out console initialization, makes code cleaner
  • Loading branch information
FromDarkHell committed Dec 20, 2020
1 parent 0a334b4 commit 9df17af
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 154 deletions.
9 changes: 7 additions & 2 deletions BL3DX11Injection/BL3DX11Injection.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>K:\Borderlands3\OakGame\Binaries\Win64\</OutDir>
<TargetName>d3d11</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
Expand Down Expand Up @@ -152,17 +154,20 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;BL3DX11INJECTION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;BL3DX11INJECTION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>d3d11.def</ModuleDefinitionFile>
<ModuleDefinitionFile>
</ModuleDefinitionFile>
<ImportLibrary>$(ProjectDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions BL3DX11Injection/ThreadManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ namespace ThreadManager {
}
}


#endif SUSPENDRESUME_H
189 changes: 37 additions & 152 deletions BL3DX11Injection/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -1,198 +1,83 @@
#include "pch.h"

#include <filesystem>
#include "dllmain.h"
#include "PluginLoadHook.h"
#include "ThreadManager.hpp"
#pragma warning(disable: 6031)
#pragma pack(1)




static HINSTANCE hL;
static HMODULE gameModule;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
// Microsoft tells us not to do like any of these things because it can cause a deadlock but if I don't do it here
// It'll end up introducing a race condition so instead I'll just do it :)
// We copy the original DX11 dll from Sys32 in order to avoid weird version differences and crashes
// The linker exports at the bottom let windows handle all of the DX11 proxy stuff after a `d3d11_org` exists in the root dir

// Suspend all threads but our own to avoid deadlocks
ThreadManager::Suspend();

// Check if the file exists to just avoid constantly copying the file on launch
std::string DX11OrgPath = FlattenString(GetModulePath()) + "\\d3d11_org.dll";
std::filesystem::remove(FlattenString(GetModulePath()) + "\\PluginLoader.log");
LogString(L"Checking for existence of " + WidenString(DX11OrgPath) + L"\n");

if (!std::filesystem::exists(DX11OrgPath)) {
// Get the path to `C:\Windows\System32\d3d11.dll` (or whatever it is for whoever's using this)
wchar_t DX11Path[MAX_PATH];
GetSystemDirectory(DX11Path, MAX_PATH);
wcscat_s(DX11Path, L"\\d3d11.dll");
LogString(L"Copying original DX11 at " + std::wstring(DX11Path) + L" to " + WidenString(DX11OrgPath) + L"\n");

// Copy the file from Sys32 over to the root directory
std::filesystem::copy(DX11Path, DX11OrgPath);
}

LogString(L"Proxy DX11 Exists: " + std::wstring(std::filesystem::exists(DX11OrgPath) ? L"Yes" : L"No") + L"\n") ;
gameModule = hModule;

DisableThreadLibraryCalls(hModule);
LogString(L"Resuming all other threads...\n");

// Resume all other threads
ThreadManager::Resume();

CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)executionThread, NULL, NULL, NULL);
}
return TRUE;
}

int executionThread() {
ThreadManager::Suspend();
std::string cmdArgs = GetCommandLineA(); // Get the command line args for our running process

// If we're running in debug mode, we wanna allocate the console
if (cmdArgs.find("--debug") != std::string::npos) {
AllocConsole(); // Allocate our console
}

SetConsoleTitle(L"Borderlands 3 Plugin Loader");

// All of this is necessary so that way we can properly use the output of the console
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stderr);
freopen("CONOUT$", "w", stdout);
HANDLE hStdout = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hStdin = CreateFile(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

// Make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
std::ios::sync_with_stdio(true);
SetStdHandle(STD_INPUT_HANDLE, hStdin);
SetStdHandle(STD_OUTPUT_HANDLE, hStdout); // Set our STD handles
SetStdHandle(STD_ERROR_HANDLE, hStdout); // stderr is going back to STDOUT

// Clear the error states for all of the C++ stream objects.
// Attempting to access the streams before they're valid causes them to enter an error state.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();

InitializeConsole();

LogString(L"Console allocated...\n");
LogString(L"==== Debug ====\n");

InitializePluginHooks(gameModule);

return TRUE;
}


#pragma region Linker Exports

#pragma comment(linker, "/export:D3D11CoreRegisterLayers=d3d11_org.D3D11CoreRegisterLayers")

#pragma comment(linker, "/export:D3D11CoreGetLayeredDeviceSize=d3d11_org.D3D11CoreGetLayeredDeviceSize")

#pragma comment(linker, "/export:D3D11CoreCreateLayeredDevice=d3d11_org.D3D11CoreCreateLayeredDevice")

#pragma comment(linker, "/export:D3D11CoreCreateDevice=d3d11_org.D3D11CoreCreateDevice")

#pragma comment(linker, "/export:D3D11CreateDeviceAndSwapChain=d3d11_org.D3D11CreateDeviceAndSwapChain")

#pragma comment(linker, "/export:D3D11CreateDevice=d3d11_org.D3D11CreateDevice")

#pragma comment(linker, "/export:EnableFeatureLevelUpgrade=d3d11_org.EnableFeatureLevelUpgrade")

#pragma comment(linker, "/export:D3DKMTWaitForSynchronizationObject=d3d11_org.D3DKMTWaitForSynchronizationObject")

#pragma comment(linker, "/export:D3DKMTUnlock=d3d11_org.D3DKMTUnlock")

#pragma comment(linker, "/export:D3DKMTSignalSynchronizationObject=d3d11_org.D3DKMTSignalSynchronizationObject")

#pragma comment(linker, "/export:D3DKMTCloseAdapter=d3d11_org.D3DKMTCloseAdapter")

#pragma comment(linker, "/export:D3DKMTCreateAllocation=d3d11_org.D3DKMTCreateAllocation")

#pragma comment(linker, "/export:D3DKMTCreateContext=d3d11_org.D3DKMTCreateContext")

#pragma comment(linker, "/export:D3DKMTCreateDevice=d3d11_org.D3DKMTCreateDevice")
// Check if the file exists to just avoid constantly copying the file on launch
std::string DX11OrgPath = FlattenString(GetModulePath()) + "\\d3d11_org.dll";
std::filesystem::remove(FlattenString(GetModulePath()) + "\\PluginLoader.log");
LogString(L"Checking for existence of " + WidenString(DX11OrgPath) + L"\n");

#pragma comment(linker, "/export:D3DKMTCreateSynchronizationObject=d3d11_org.D3DKMTCreateSynchronizationObject")
// We copy the original DX11 dll from Sys32 in order to avoid weird version differences and crashes
// The linker exports at the bottom let windows handle all of the DX11 proxy stuff after a `d3d11_org` exists in the root dir

#pragma comment(linker, "/export:D3DKMTDestroyAllocation=d3d11_org.D3DKMTDestroyAllocation")
if (!std::filesystem::exists(DX11OrgPath)) {
// Get the path to `C:\Windows\System32\d3d11.dll` (or whatever it is for whoever's using this)
wchar_t DX11Path[MAX_PATH];
GetSystemDirectory(DX11Path, MAX_PATH);
wcscat_s(DX11Path, L"\\d3d11.dll");
LogString(L"Copying original DX11 at " + std::wstring(DX11Path) + L" to " + WidenString(DX11OrgPath) + L"\n");

#pragma comment(linker, "/export:D3DKMTDestroyContext=d3d11_org.D3DKMTDestroyContext")

#pragma comment(linker, "/export:D3DKMTDestroyDevice=d3d11_org.D3DKMTDestroyDevice")

#pragma comment(linker, "/export:D3DKMTDestroySynchronizationObject=d3d11_org.D3DKMTDestroySynchronizationObject")

#pragma comment(linker, "/export:D3DKMTGetSharedPrimaryHandle=d3d11_org.D3DKMTGetSharedPrimaryHandle")

#pragma comment(linker, "/export:D3DKMTGetContextSchedulingPriority=d3d11_org.D3DKMTGetContextSchedulingPriority")

#pragma comment(linker, "/export:D3DKMTSetVidPnSourceOwner=d3d11_org.D3DKMTSetVidPnSourceOwner")

#pragma comment(linker, "/export:D3DKMTGetDisplayModeList=d3d11_org.D3DKMTGetDisplayModeList")

#pragma comment(linker, "/export:D3DKMTGetMultisampleMethodList=d3d11_org.D3DKMTGetMultisampleMethodList")

#pragma comment(linker, "/export:D3DKMTGetRuntimeData=d3d11_org.D3DKMTGetRuntimeData")

#pragma comment(linker, "/export:D3DKMTSetGammaRamp=d3d11_org.D3DKMTSetGammaRamp")

#pragma comment(linker, "/export:D3DKMTLock=d3d11_org.D3DKMTLock")

#pragma comment(linker, "/export:D3DKMTSetDisplayPrivateDriverFormat=d3d11_org.D3DKMTSetDisplayPrivateDriverFormat")

#pragma comment(linker, "/export:D3DKMTSetDisplayMode=d3d11_org.D3DKMTSetDisplayMode")

#pragma comment(linker, "/export:D3DKMTPresent=d3d11_org.D3DKMTPresent")

#pragma comment(linker, "/export:D3DKMTSetContextSchedulingPriority=d3d11_org.D3DKMTSetContextSchedulingPriority")

#pragma comment(linker, "/export:D3DKMTQueryAllocationResidency=d3d11_org.D3DKMTQueryAllocationResidency")

#pragma comment(linker, "/export:D3DKMTSetAllocationPriority=d3d11_org.D3DKMTSetAllocationPriority")

#pragma comment(linker, "/export:D3DKMTRender=d3d11_org.D3DKMTRender")

#pragma comment(linker, "/export:D3DKMTWaitForVerticalBlankEvent=d3d11_org.D3DKMTWaitForVerticalBlankEvent")

#pragma comment(linker, "/export:D3D11CreateDeviceForD3D12=d3d11_org.D3D11CreateDeviceForD3D12")

#pragma comment(linker, "/export:D3D11On12CreateDevice=d3d11_org.D3D11On12CreateDevice")

#pragma comment(linker, "/export:D3DPerformance_BeginEvent=d3d11_org.D3DPerformance_BeginEvent")

#pragma comment(linker, "/export:D3DPerformance_EndEvent=d3d11_org.D3DPerformance_EndEvent")

#pragma comment(linker, "/export:D3DPerformance_GetStatus=d3d11_org.D3DPerformance_GetStatus")

#pragma comment(linker, "/export:D3DPerformance_SetMarker=d3d11_org.D3DPerformance_SetMarker")

#pragma comment(linker, "/export:D3DKMTQueryAdapterInfo=d3d11_org.D3DKMTQueryAdapterInfo")
// Copy the file from Sys32 over to the root directory
std::filesystem::copy(DX11Path, DX11OrgPath);
}

#pragma comment(linker, "/export:OpenAdapter10=d3d11_org.OpenAdapter10")
LogString(L"Proxy DX11 Exists: " + std::wstring(std::filesystem::exists(DX11OrgPath) ? L"Yes" : L"No") + L"\n");
hL = LoadLibrary(L".\\d3d11_org.dll");
if (!hL) {
MessageBox(NULL, L"Unable to load proxy dll...", L"Hi", NULL);
return 0;
}

#pragma comment(linker, "/export:OpenAdapter10_2=d3d11_org.OpenAdapter10_2")
LogString(L"Resuming all other threads...\n");

#pragma comment(linker, "/export:D3DKMTEscape=d3d11_org.D3DKMTEscape")
// Resume all other threads
ThreadManager::Resume();

#pragma comment(linker, "/export:D3DKMTGetDeviceState=d3d11_org.D3DKMTGetDeviceState")
InitializePluginHooks(gameModule);

#pragma comment(linker, "/export:D3DKMTOpenAdapterFromHdc=d3d11_org.D3DKMTOpenAdapterFromHdc")
return TRUE;
}

#pragma comment(linker, "/export:D3DKMTOpenResource=d3d11_org.D3DKMTOpenResource")

#pragma comment(linker, "/export:D3DKMTQueryResourceInfo=d3d11_org.D3DKMTQueryResourceInfo")
#pragma region Linker Exports
#pragma comment(linker, "/export:D3D11CoreCreateDevice=d3d11_org.D3D11CoreCreateDevice")

#pragma comment(linker, "/export:CreateDirect3D11DeviceFromDXGIDevice=d3d11_org.CreateDirect3D11DeviceFromDXGIDevice")
#pragma comment(linker, "/export:D3D11CreateDevice=d3d11_org.D3D11CreateDevice")

#pragma comment(linker, "/export:CreateDirect3D11SurfaceFromDXGISurface=d3d11_org.CreateDirect3D11SurfaceFromDXGISurface")
#pragma comment(linker, "/export:D3D11CreateDeviceAndSwapChain=d3d11_org.D3D11CreateDeviceAndSwapChain")

#pragma endregion
27 changes: 27 additions & 0 deletions BL3DX11Injection/pch.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "pch.h"

#pragma warning(disable: 6031)

std::wstring GetLastErrorAsString()
{
Expand Down Expand Up @@ -49,6 +50,32 @@ std::wstring GetModulePath() {
}
}

void InitializeConsole() {
SetConsoleTitle(L"Borderlands 3 Plugin Loader");

// All of this is necessary so that way we can properly use the output of the console
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stderr);
freopen("CONOUT$", "w", stdout);
HANDLE hStdout = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hStdin = CreateFile(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

// Make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
SetStdHandle(STD_INPUT_HANDLE, hStdin);
SetStdHandle(STD_OUTPUT_HANDLE, hStdout); // Set our STD handles
SetStdHandle(STD_ERROR_HANDLE, hStdout); // stderr is going back to STDOUT

// Clear the error states for all of the C++ stream objects.
// Attempting to access the streams before they're valid causes them to enter an error state.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();

}

void LogString(const std::wstring& str) {
std::wcout << str;

Expand Down
2 changes: 2 additions & 0 deletions BL3DX11Injection/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ std::string FlattenString(const std::wstring& s);

std::wstring GetModulePath();

void InitializeConsole();

void LogString(const std::wstring& str);

#endif //PCH_H

0 comments on commit 9df17af

Please sign in to comment.