Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Client/multiplayer_sa/CMultiplayerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ void CMultiplayerSA::InitHooks()
MemSet((void*)0x6C4453, 0x90, 0x68);

InitHooks_CrashFixHacks();
InitHooks_DeviceSelection();

// Init our 1.3 hooks.
Init_13();
Expand Down
1 change: 1 addition & 0 deletions Client/multiplayer_sa/CMultiplayerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class CMultiplayerSA : public CMultiplayer
void InitHooks_ProjectileCollisionFix();
void InitHooks_ObjectStreamerOptimization();
void InitHooks_Postprocess();
void InitHooks_DeviceSelection();
CRemoteDataStorage* CreateRemoteDataStorage();
void DestroyRemoteDataStorage(CRemoteDataStorage* pData);
void AddRemoteDataStorage(CPlayerPed* pPed, CRemoteDataStorage* pData);
Expand Down
157 changes: 157 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"

#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif

// This is copied from SilentPatch:
// https://github.com/CookiePLMonster/SilentPatch/blob/dev/SilentPatch/FriendlyMonitorNames.cpp
std::map<std::string, std::string, std::less<>> GetFriendlyMonitorNamesForDevicePaths()
{
std::map<std::string, std::string, std::less<>> monitorNames;

#if WINVER < _WIN32_WINNT_WIN7
return monitorNames;
#else
HMODULE user32Lib = LoadLibrary(TEXT("user32"));
if (user32Lib != nullptr)
{
auto getDisplayConfigBufferSizes = (decltype(GetDisplayConfigBufferSizes)*)GetProcAddress(user32Lib, "GetDisplayConfigBufferSizes");
auto queryDisplayConfig = (decltype(QueryDisplayConfig)*)GetProcAddress(user32Lib, "QueryDisplayConfig");
auto displayConfigGetDeviceInfo = (decltype(DisplayConfigGetDeviceInfo)*)GetProcAddress(user32Lib, "DisplayConfigGetDeviceInfo");
if (getDisplayConfigBufferSizes != nullptr && queryDisplayConfig != nullptr && displayConfigGetDeviceInfo != nullptr)
{
UINT32 pathCount, modeCount;
std::unique_ptr<DISPLAYCONFIG_PATH_INFO[]> paths;
std::unique_ptr<DISPLAYCONFIG_MODE_INFO[]> modes;

LONG result = ERROR_SUCCESS;
do
{
result = getDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount);
if (result != ERROR_SUCCESS)
{
break;
}
paths = std::make_unique<DISPLAYCONFIG_PATH_INFO[]>(pathCount);
modes = std::make_unique<DISPLAYCONFIG_MODE_INFO[]>(modeCount);
result = queryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.get(), &modeCount, modes.get(), nullptr);
} while (result == ERROR_INSUFFICIENT_BUFFER);

if (result == ERROR_SUCCESS)
{
for (size_t i = 0; i < pathCount; i++)
{
DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
targetName.header.adapterId = paths[i].targetInfo.adapterId;
targetName.header.id = paths[i].targetInfo.id;
targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = sizeof(targetName);
const LONG targetNameResult = DisplayConfigGetDeviceInfo(&targetName.header);

DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {};
sourceName.header.adapterId = paths[i].sourceInfo.adapterId;
sourceName.header.id = paths[i].sourceInfo.id;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof(sourceName);
const LONG sourceNameResult = DisplayConfigGetDeviceInfo(&sourceName.header);
if (targetNameResult == ERROR_SUCCESS && sourceNameResult == ERROR_SUCCESS && targetName.monitorFriendlyDeviceName[0] != '\0')
{
char gdiDeviceName[std::size(sourceName.viewGdiDeviceName)];
char monitorFriendlyDeviceName[std::size(targetName.monitorFriendlyDeviceName)];
WideCharToMultiByte(CP_ACP, 0, sourceName.viewGdiDeviceName, -1, gdiDeviceName, static_cast<int>(std::size(gdiDeviceName)), nullptr,
nullptr);
WideCharToMultiByte(CP_ACP, 0, targetName.monitorFriendlyDeviceName, -1, monitorFriendlyDeviceName,
static_cast<int>(std::size(monitorFriendlyDeviceName)), nullptr, nullptr);

monitorNames.try_emplace(gdiDeviceName, monitorFriendlyDeviceName);
}
}
}
}
FreeLibrary(user32Lib);
}

return monitorNames;
#endif
}

struct RwSubSystemInfo
{
char name[80];
};

#define FUNC_rwDeviceSystemRequest 0x7F2AB0
using rwDeviceSystemRequest = RwSubSystemInfo*(__cdecl*)(void* device, uint32_t requestId, RwSubSystemInfo* pOut, void* pInOut, uint32_t numIn);
static RwSubSystemInfo* RwEngineGetSubSystemInfo_Hooked(RwSubSystemInfo* subSystemInfo, int32_t subSystemIndex)
{
static auto rwDeviceSystemRequestFunc = (rwDeviceSystemRequest)(FUNC_rwDeviceSystemRequest);
auto devicePointer = *(uint32_t*)(0xC97B24);
auto result = rwDeviceSystemRequestFunc((void*)(devicePointer + 0x10), 14, subSystemInfo, nullptr, subSystemIndex);
if (result == nullptr)
return nullptr;

auto pDxDevice = *(IDirect3D9**)0xC97C20;
if (pDxDevice == nullptr)
return subSystemInfo;

D3DADAPTER_IDENTIFIER9 identifier;
if (FAILED(pDxDevice->GetAdapterIdentifier(subSystemIndex, 0, &identifier)))
return subSystemInfo;

static const auto friendlyNames = GetFriendlyMonitorNamesForDevicePaths();

// If we can't find the friendly name, either because it doesn't exist or we're on an ancient Windows, fall back to the device name
auto it = friendlyNames.find(identifier.DeviceName);
if (it != friendlyNames.end())
{
strncpy_s(subSystemInfo->name, it->second.c_str(), _TRUNCATE);
}
else
{
strncpy_s(subSystemInfo->name, identifier.Description, _TRUNCATE);
}

return subSystemInfo;
}

#define FUNC_DialogFunc 0x745E50
static INT_PTR CALLBACK CustomDlgProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
auto orgDialogFunc = (DLGPROC)FUNC_DialogFunc;
if (msg == WM_INITDIALOG)
{
orgDialogFunc(window, msg, wParam, lParam);

// Set Icon
HMODULE hGameModule = GetModuleHandle(nullptr);
SendMessage(window, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(LoadIcon(hGameModule, MAKEINTRESOURCE(100))));

// Make the dialog visible in the task bar
// https://stackoverflow.com/a/1462811
SetWindowLongPtr(window, GWL_EXSTYLE, WS_EX_APPWINDOW);
ShowWindow(window, SW_HIDE);
ShowWindow(window, SW_SHOW);
return FALSE;
}

return orgDialogFunc(window, msg, wParam, lParam);
}

void CMultiplayerSA::InitHooks_DeviceSelection()
{
MemPut<DLGPROC>(0x746239, (DLGPROC)&CustomDlgProc);
HookInstall(0x7F2C30, (DWORD)RwEngineGetSubSystemInfo_Hooked, 6);
}
Loading