Skip to content
This repository was archived by the owner on Mar 5, 2024. It is now read-only.

Commit 8c51db1

Browse files
committed
Cherry-pick 32e4995
1 parent a465c66 commit 8c51db1

File tree

7 files changed

+220
-83
lines changed

7 files changed

+220
-83
lines changed

tf2_bot_detector/Platform/Windows/Windows.cpp

Lines changed: 60 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1+
#include <ntstatus.h>
2+
#define WIN32_NO_STATUS
3+
14
#include "Platform/Platform.h"
5+
#include "Platform/PlatformCommon.h"
26
#include "Util/TextUtils.h"
37
#include "Log.h"
48
#include "WindowsHelpers.h"
59
#include "tf2_bot_detector_winrt.h"
610

711
#include <mh/error/ensure.hpp>
12+
#include <mh/error/exception_details.hpp>
813
#include <mh/text/codecvt.hpp>
914
#include <mh/text/format.hpp>
1015
#include <mh/text/formatters/error_code.hpp>
1116
#include <mh/text/stringops.hpp>
1217

1318
#define WIN32_LEAN_AND_MEAN 1
1419
#include <Windows.h>
15-
#include <minappmodel.h>
1620
#include <Shlobj.h>
17-
#include <versionhelpers.h>
21+
#include <winternl.h>
1822

1923
using namespace tf2_bot_detector;
2024
using namespace std::string_view_literals;
@@ -35,73 +39,6 @@ static std::filesystem::path GetKnownFolderPath(const KNOWNFOLDERID& id)
3539
return retVal;
3640
}
3741

38-
static void* GetProcAddressHelper(const wchar_t* moduleName, const char* symbolName, bool isCritical = false, MH_SOURCE_LOCATION_AUTO(location))
39-
{
40-
if (!moduleName)
41-
throw std::invalid_argument("moduleName was nullptr");
42-
if (!moduleName[0])
43-
throw std::invalid_argument("moduleName was empty");
44-
if (!symbolName)
45-
throw std::invalid_argument("symbolName was nullptr");
46-
if (!symbolName[0])
47-
throw std::invalid_argument("symbolName was empty");
48-
49-
HMODULE moduleHandle = GetModuleHandleW(moduleName);
50-
if (!moduleHandle)
51-
{
52-
auto err = GetLastError();
53-
throw std::system_error(err, std::system_category(), mh::format("Failed to GetModuleHandle({})", mh::change_encoding<char>(moduleName)));
54-
}
55-
56-
auto address = GetProcAddress(moduleHandle, symbolName);
57-
if (!address)
58-
{
59-
auto err = GetLastError();
60-
auto ec = std::error_code(err, std::system_category());
61-
62-
auto msg = mh::format("{}: Failed to find function {} in {}", location, symbolName, mh::change_encoding<char>(moduleName));
63-
64-
if (!isCritical)
65-
DebugLogWarning(location, "{}: {}", msg, ec);
66-
else
67-
throw std::system_error(ec, msg);
68-
}
69-
70-
return address;
71-
}
72-
73-
namespace tf2_bot_detector
74-
{
75-
static const std::wstring& GetCurrentPackageFamilyName()
76-
{
77-
static const std::wstring s_CurrentPackageFamilyName = []() -> std::wstring
78-
{
79-
WCHAR name[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1];
80-
UINT32 nameLength = UINT32(std::size(name));
81-
82-
using func_type = LONG(*)(UINT32* packageFamilyNameLength, PWSTR packageFamilyName);
83-
84-
const auto func = reinterpret_cast<func_type>(GetProcAddressHelper(L"Kernel32.dll", "GetCurrentPackageFamilyName", true));
85-
86-
const auto errc = func(&nameLength, name);
87-
88-
switch (errc)
89-
{
90-
case ERROR_SUCCESS:
91-
return std::wstring(name, nameLength > 0 ? (nameLength - 1) : 0);
92-
case APPMODEL_ERROR_NO_PACKAGE:
93-
return {};
94-
case ERROR_INSUFFICIENT_BUFFER:
95-
throw std::runtime_error(mh::format("{}: Buffer too small", __FUNCTION__));
96-
default:
97-
throw std::runtime_error(mh::format("{}: Unknown error {}", __FUNCTION__, errc));
98-
}
99-
}();
100-
101-
return s_CurrentPackageFamilyName;
102-
}
103-
}
104-
10542
namespace
10643
{
10744
class FallbackWinRTInterface final : public tf2_bot_detector::WinRT
@@ -119,21 +56,59 @@ namespace
11956
{
12057
return std::filesystem::temp_directory_path();
12158
}
59+
std::wstring GetCurrentPackageFamilyName() const override
60+
{
61+
return {};
62+
}
63+
const mh::exception_details_handler& GetWinRTExceptionDetailsHandler() const override
64+
{
65+
assert(!"This should never be called in the first place");
66+
67+
class Handler final : public mh::exception_details_handler
68+
{
69+
public:
70+
bool try_handle(const std::exception_ptr& e, mh::exception_details& details) const noexcept override
71+
{
72+
return false;
73+
}
74+
} static const s_Handler;
75+
76+
return s_Handler;
77+
}
12278
};
12379
}
12480

81+
static bool IsReallyWindows10OrGreater()
82+
{
83+
using RtlGetVersionFn = NTSTATUS(*)(PRTL_OSVERSIONINFOW lpVersionInformation);
84+
85+
static const auto s_RtlGetVersionFn = reinterpret_cast<RtlGetVersionFn>(
86+
tf2_bot_detector::Platform::GetProcAddressHelper("ntdll.dll", "RtlGetVersion", true));
87+
88+
RTL_OSVERSIONINFOW info{};
89+
info.dwOSVersionInfoSize = sizeof(info);
90+
const auto result = s_RtlGetVersionFn(&info);
91+
assert(result == STATUS_SUCCESS);
92+
93+
return info.dwMajorVersion >= 10;
94+
}
95+
12596
static const tf2_bot_detector::WinRT* GetWinRTInterface()
12697
{
12798
struct WinRTHelper
12899
{
129100
WinRTHelper()
130101
{
131-
constexpr wchar_t WINRT_DLL_NAME[] = L"tf2_bot_detector_winrt.dll";
132-
m_Module = mh_ensure(LoadLibraryW(WINRT_DLL_NAME));
102+
constexpr char WINRT_DLL_NAME[] = "tf2_bot_detector_winrt.dll";
103+
m_Module = mh_ensure(LoadLibraryA(WINRT_DLL_NAME));
133104

134105
CreateWinRTInterfaceFn func = reinterpret_cast<CreateWinRTInterfaceFn>(GetProcAddressHelper(WINRT_DLL_NAME, "CreateWinRTInterface"));
135106

136107
m_WinRT.reset(func());
108+
109+
struct DummyType {};
110+
m_ExceptionDetailsHandler = mh::exception_details::add_handler(
111+
typeid(DummyType), m_WinRT->GetWinRTExceptionDetailsHandler());
137112
}
138113
WinRTHelper(WinRTHelper&& other) noexcept :
139114
m_Module(std::exchange(other.m_Module, nullptr)),
@@ -167,19 +142,24 @@ static const tf2_bot_detector::WinRT* GetWinRTInterface()
167142

168143
HMODULE m_Module{};
169144
std::unique_ptr<WinRT> m_WinRT;
145+
mh::exception_details::handler m_ExceptionDetailsHandler;
170146
};
171147

172-
static std::optional<WinRTHelper> s_Helper = []() -> std::optional<WinRTHelper>
148+
static const tf2_bot_detector::WinRT* s_Value = []() -> const tf2_bot_detector::WinRT*
173149
{
174-
std::optional<WinRTHelper> helper;
175-
if (IsWindows10OrGreater())
176-
helper.emplace();
177-
178-
return std::move(helper);
150+
if (IsReallyWindows10OrGreater())
151+
{
152+
static WinRTHelper s_Helper;
153+
return s_Helper.m_WinRT.get();
154+
}
155+
else
156+
{
157+
static const FallbackWinRTInterface s_FallbackInterface;
158+
return &s_FallbackInterface;
159+
}
179160
}();
180-
static const FallbackWinRTInterface s_FallbackInterface;
181161

182-
return s_Helper.has_value() ? s_Helper->m_WinRT.get() : &s_FallbackInterface;
162+
return s_Value;
183163
}
184164

185165
std::filesystem::path tf2_bot_detector::Platform::GetCurrentExeDir()
@@ -199,7 +179,7 @@ std::filesystem::path tf2_bot_detector::Platform::GetCurrentExeDir()
199179

200180
std::filesystem::path tf2_bot_detector::Platform::GetLegacyAppDataDir()
201181
{
202-
auto packageFamilyName = GetCurrentPackageFamilyName();
182+
auto packageFamilyName = GetWinRTInterface()->GetCurrentPackageFamilyName();
203183
if (packageFamilyName.empty())
204184
return {};
205185

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
cmake_minimum_required(VERSION 3.17)
2-
project(tf2_bot_detector_common)
2+
3+
include(../cmake/init-preproject.cmake)
4+
project(tf2_bot_detector_common)
5+
include(../cmake/init-postproject.cmake)
36

47
add_library(tf2_bot_detector_common STATIC)
58
add_library(tf2_bot_detector::common ALIAS tf2_bot_detector_common)
69

710
target_sources(tf2_bot_detector_common PRIVATE
811
"include/ReleaseChannel.h"
9-
"src/Placeholder.cpp"
12+
"include/Platform/PlatformCommon.h"
1013
)
1114

15+
if (WIN32)
16+
target_sources(tf2_bot_detector_common PRIVATE
17+
"src/Platform/Windows/PlatformCommon.cpp"
18+
)
19+
endif()
20+
1221
target_include_directories(tf2_bot_detector_common PUBLIC "include")
1322

23+
find_package(fmt CONFIG REQUIRED)
24+
1425
target_link_libraries(tf2_bot_detector_common
1526
PUBLIC
1627
mh::stuff
28+
fmt::fmt
1729
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
#include <mh/source_location.hpp>
4+
5+
namespace tf2_bot_detector::Platform
6+
{
7+
void* GetProcAddressHelper(const char* moduleName, const char* symbolName, bool isCritical = false, MH_SOURCE_LOCATION_AUTO(location));
8+
}

tf2_bot_detector_common/src/Placeholder.cpp

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "Platform/PlatformCommon.h"
2+
3+
#include <mh/text/format.hpp>
4+
5+
#include <stdexcept>
6+
7+
#include <Windows.h>
8+
9+
void* tf2_bot_detector::Platform::GetProcAddressHelper(const char* moduleName, const char* symbolName,
10+
bool isCritical, const mh::source_location& location)
11+
{
12+
if (!moduleName)
13+
throw std::invalid_argument("moduleName was nullptr");
14+
if (!moduleName[0])
15+
throw std::invalid_argument("moduleName was empty");
16+
if (!symbolName)
17+
throw std::invalid_argument("symbolName was nullptr");
18+
if (!symbolName[0])
19+
throw std::invalid_argument("symbolName was empty");
20+
21+
HMODULE moduleHandle = GetModuleHandleA(moduleName);
22+
if (!moduleHandle)
23+
{
24+
auto err = GetLastError();
25+
throw std::system_error(err, std::system_category(), mh::format(MH_FMT_STRING("Failed to GetModuleHandle({})"), moduleName));
26+
}
27+
28+
auto address = GetProcAddress(moduleHandle, symbolName);
29+
if (!address)
30+
{
31+
auto err = GetLastError();
32+
auto ec = std::error_code(err, std::system_category());
33+
34+
if (isCritical)
35+
{
36+
throw std::system_error(ec, mh::format(MH_FMT_STRING("{}: Failed to find function {} in {}"), location, symbolName, moduleName));
37+
}
38+
}
39+
40+
return address;
41+
}

0 commit comments

Comments
 (0)