1
0
mirror of synced 2024-11-11 22:07:09 +01:00

VS 2019 compilation ok

This commit is contained in:
Reaver 2019-06-03 19:25:47 +03:00
parent 2f02d74d26
commit d130815f0d
7 changed files with 609 additions and 597 deletions

View File

@ -2,6 +2,7 @@
#include <Utility/InitFunction.h>
#include "Global.h"
#include "Utility/GameDetect.h"
#include "Utility/Hooking.Patterns.h"
#pragma optimize("", off)
void *__cdecl memcpy_0(void *a1, const void *a2, size_t a3)
@ -190,9 +191,51 @@ void init_windowHooks(windowHooks* data)
}
/* END WINDOW HOOKS */
void InitializeHints()
{
static std::string modPath;
if (modPath.empty())
{
char exeName[512];
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
char* exeBaseName = strrchr(exeName, '\\');
exeBaseName[0] = L'\0';
modPath = exeName;
modPath += "\\";
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
modPath = exeName;
modPath += "\\";
}
std::string hintsFile = modPath + "hints.dat";
FILE* hints = fopen(hintsFile.c_str(), "rb");
if (hints)
{
while (!feof(hints))
{
uint64_t hash;
uintptr_t hint;
fread(&hash, 1, sizeof(hash), hints);
fread(&hint, 1, sizeof(hint), hints);
hook::pattern::hint(hash, hint);
}
fclose(hints);
}
}
static InitFunction globalFunc([]()
{
InitializeHints();
CreateThread(NULL, 0, QuitGameThread, NULL, 0, NULL);
}, GameID::Global);
#pragma optimize("", on)

View File

@ -5,37 +5,77 @@
* regarding licensing.
*/
#include "StdInc.h"
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include "Hooking.Patterns.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <algorithm>
#include <string_view>
#if PATTERNS_USE_HINTS
#include <map>
static void Citizen_PatternSaveHint(uint64_t hash, uintptr_t hint)
{
static std::string modPath;
if (modPath.empty())
{
char exeName[512];
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
char* exeBaseName = strrchr(exeName, '\\');
exeBaseName[0] = L'\0';
modPath = exeName;
modPath += "\\";
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
modPath = exeName;
modPath += "\\";
}
std::string hintsFile = modPath + "hints.dat";
FILE* hints = fopen(hintsFile.c_str(), "ab");
if (hints)
{
fwrite(&hash, 1, sizeof(hash), hints);
fwrite(&hint, 1, sizeof(hint), hints);
fclose(hints);
}
}
#endif
#if PATTERNS_USE_HINTS
// from boost someplace
template <std::uint64_t FnvPrime, std::uint64_t OffsetBasis>
struct basic_fnv_1
{
std::uint64_t operator()(const char *text) const
{
std::uint64_t hash = OffsetBasis;
std::uint64_t operator()(std::string_view text) const
{
std::uint64_t hash = OffsetBasis;
for (auto it : text)
{
hash *= FnvPrime;
hash ^= it;
}
while (*text != 0)
{
hash *= FnvPrime;
hash ^= *(uint8_t *)text;
++text;
}
return hash;
}
return hash;
}
};
const std::uint64_t fnv_prime = 1099511628211u;
@ -47,304 +87,275 @@ typedef basic_fnv_1<fnv_prime, fnv_offset_basis> fnv_1;
namespace hook
{
ptrdiff_t baseAddressDifference;
inline std::multimap<uint64_t, uintptr_t>& GetHints()
{
static std::multimap<uint64_t, uintptr_t> hints;
return hints;
}
// sets the base to the process main base
void set_base()
{
set_base((uintptr_t)GetModuleHandle(nullptr));
}
static void TransformPattern(std::string_view pattern, std::string& data, std::string& mask)
{
uint8_t tempDigit = 0;
bool tempFlag = false;
auto tol = [](char ch) -> uint8_t
{
if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
return uint8_t(ch - '0');
};
for (auto ch : pattern)
{
if (ch == ' ')
{
continue;
}
else if (ch == '?')
{
data.push_back(0);
mask.push_back('?');
}
else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
{
uint8_t thisDigit = tol(ch);
if (!tempFlag)
{
tempDigit = thisDigit << 4;
tempFlag = true;
}
else
{
tempDigit |= thisDigit;
tempFlag = false;
data.push_back(tempDigit);
mask.push_back('x');
}
}
}
}
class executable_meta
{
private:
uintptr_t m_begin;
uintptr_t m_end;
public:
template<typename TReturn, typename TOffset>
TReturn* getRVA(TOffset rva)
{
return (TReturn*)(m_begin + rva);
}
explicit executable_meta(void* module)
: m_begin((uintptr_t)module)
{
PIMAGE_DOS_HEADER dosHeader = getRVA<IMAGE_DOS_HEADER>(0);
PIMAGE_NT_HEADERS ntHeader = getRVA<IMAGE_NT_HEADERS>(dosHeader->e_lfanew);
m_end = m_begin + ntHeader->OptionalHeader.SizeOfImage;
}
executable_meta(uintptr_t begin, uintptr_t end)
: m_begin(begin), m_end(end)
{
}
inline uintptr_t begin() const { return m_begin; }
inline uintptr_t end() const { return m_end; }
};
void pattern::Initialize(const char* pattern, size_t length)
{
// get the hash for the base pattern
#if PATTERNS_USE_HINTS
static std::multimap<uint64_t, uintptr_t> g_hints;
m_hash = fnv_1()(std::string_view(pattern, length));
#endif
static void TransformPattern(const char *pattern, std::vector<uint8_t>& data, std::vector<uint8_t>& mask)
{
auto tol = [](char ch) -> uint8_t
{
if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
return uint8_t(ch - '0');
};
// transform the base pattern from IDA format to canonical format
TransformPattern(std::string_view(pattern, length), m_bytes, m_mask);
auto is_digit = [](char ch) -> bool
{
return (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f') || (ch >= '0' && ch <= '9');
};
char temp_string[2]{ 0, 0 };
data.clear();
mask.clear();
if (!pattern)
{
return;
}
const char *patit = pattern;
const char *patend = (pattern + strlen(pattern) + 1);
while (patit != patend)
{
char ch = *patit;
if (ch == ' ' || ch == 0)
{
if (!temp_string[0] && !temp_string[1]) //Continous delimiter
{
}
else if (temp_string[0] == '?' && (temp_string[1] == '?' || temp_string[1] == 0)) //??
{
data.push_back(0);
mask.push_back(0u);
}
else if (temp_string[0] == '?' && is_digit(temp_string[1])) //?x
{
data.push_back(tol(temp_string[1]));
mask.push_back(0x0Fu);
}
else if (temp_string[1] == '?' && is_digit(temp_string[0])) //x?
{
data.push_back(tol(temp_string[0]) << 4);
mask.push_back(0xF0u);
}
else if (is_digit(temp_string[0]) && is_digit(temp_string[1])) //xx
{
data.push_back((tol(temp_string[0]) << 4) | tol(temp_string[1]));
mask.push_back(0xFFu);
}
else
{
data.clear();
mask.clear();
return;
}
temp_string[0] = 0;
temp_string[1] = 0;
}
else
{
if (temp_string[0] == 0)
{
temp_string[0] = ch;
}
else if (temp_string[1] == 0)
{
temp_string[1] = ch;
}
else
{
data.clear();
mask.clear();
return;
}
}
++patit;
}
}
class executable_meta
{
private:
uintptr_t m_begin;
uintptr_t m_end;
public:
template<typename TReturn, typename TOffset>
TReturn* getRVA(TOffset rva)
{
return (TReturn*)(m_begin + rva);
}
explicit executable_meta(void* module)
: m_begin((uintptr_t)module), m_end(0)
{
static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER
{
return reinterpret_cast<PIMAGE_SECTION_HEADER>(
(UCHAR*)nt_headers->OptionalHeader.DataDirectory +
nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) +
section * sizeof(IMAGE_SECTION_HEADER));
};
PIMAGE_DOS_HEADER dosHeader = getRVA<IMAGE_DOS_HEADER>(0);
PIMAGE_NT_HEADERS ntHeader = getRVA<IMAGE_NT_HEADERS>(dosHeader->e_lfanew);
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
{
auto sec = getSection(ntHeader, i);
auto secSize = sec->SizeOfRawData != 0 ? sec->SizeOfRawData : sec->Misc.VirtualSize;
//if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE)
m_end = m_begin + sec->VirtualAddress + secSize;
if ((i == ntHeader->FileHeader.NumberOfSections - 1) && m_end == 0)
m_end = m_begin + sec->PointerToRawData + secSize;
}
}
executable_meta(uintptr_t begin, uintptr_t end)
: m_begin(begin), m_end(end)
{
}
inline uintptr_t begin() const { return m_begin; }
inline uintptr_t end() const { return m_end; }
};
void pattern::Initialize(const char* pattern)
{
// get the hash for the base pattern
#if PATTERNS_USE_HINTS
m_hash = fnv_1()(pattern);
// if there's hints, try those first
if (m_module == GetModuleHandle(nullptr))
{
auto range = GetHints().equal_range(m_hash);
if (range.first != range.second)
{
std::for_each(range.first, range.second, [&](const std::pair<uint64_t, uintptr_t>& hint)
{
ConsiderMatch(hint.second);
});
// if the hints succeeded, we don't need to do anything more
if (!m_matches.empty())
{
m_matched = true;
return;
}
}
}
#endif
}
// transform the base pattern from IDA format to canonical format
TransformPattern(pattern, m_bytes, m_mask);
void pattern::EnsureMatches(uint32_t maxCount)
{
if (m_matched)
{
return;
}
m_size = m_mask.size();
// scan the executable for code
executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_module);
auto matchSuccess = [&](uintptr_t address)
{
#if PATTERNS_USE_HINTS
// if there's hints, try those first
if (m_module == GetModuleHandle(nullptr))
{
auto range = g_hints.equal_range(m_hash);
if (range.first != range.second)
{
std::for_each(range.first, range.second, [&] (const std::pair<uint64_t, uintptr_t>& hint)
{
ConsiderMatch(hint.second);
});
// if the hints succeeded, we don't need to do anything more
if (!m_matches.empty())
{
m_matched = true;
return;
}
}
}
#endif
}
void pattern::EnsureMatches(uint32_t maxCount)
{
if (m_matched)
return;
if (!m_rangeStart && !m_rangeEnd && !m_module)
return;
// scan the executable for code
executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_module);
auto matchSuccess = [&] (uintptr_t address)
{
#if PATTERNS_USE_HINTS
g_hints.emplace(m_hash, address);
GetHints().emplace(m_hash, address);
Citizen_PatternSaveHint(m_hash, address);
#else
(void)address;
(void)address;
#endif
return (m_matches.size() == maxCount);
};
return (m_matches.size() == maxCount);
};
ptrdiff_t BadCharacter[256];
const uint8_t* pattern = reinterpret_cast<const uint8_t*>(m_bytes.c_str());
const char* mask = m_mask.c_str();
size_t maskSize = m_mask.size();
size_t lastWild = m_mask.find_last_of('?');
std::ptrdiff_t index;
ptrdiff_t Last[256];
const std::uint8_t *pbytes = m_bytes.data();
const std::uint8_t *pmask = m_mask.data();
std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast<ptrdiff_t>(lastWild));
for (std::uint32_t bc = 0; bc < 256; ++bc)
{
for (index = m_size - 1; index >= 0; --index)
{
if ((pbytes[index] & pmask[index]) == (bc & pmask[index]))
{
break;
}
}
for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(maskSize); ++i)
{
if (Last[pattern[i]] < i)
{
Last[pattern[i]] = i;
}
}
BadCharacter[bc] = index;
}
for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;)
{
uint8_t* ptr = reinterpret_cast<uint8_t*>(i);
ptrdiff_t j = maskSize - 1;
__try
{
for (uintptr_t i = executable.begin(), end = executable.end() - m_size; i <= end;)
{
uint8_t* ptr = reinterpret_cast<uint8_t*>(i);
while ((j >= 0) && (mask[j] == '?' || pattern[j] == ptr[j])) j--;
for (index = m_size - 1; index >= 0; --index)
{
if ((pbytes[index] & pmask[index]) != (ptr[index] & pmask[index]))
{
break;
}
}
if (j < 0)
{
m_matches.emplace_back(ptr);
if (index == -1)
{
m_matches.emplace_back(ptr);
if (matchSuccess(i))
{
break;
}
i++;
}
else i += std::max((ptrdiff_t)1, j - Last[ptr[j]]);
}
if (matchSuccess(i))
{
break;
}
m_matched = true;
}
i += m_size;
}
else
{
i += max(index - BadCharacter[ptr[index]], 1);
}
}
}
__except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{ }
m_matched = true;
}
bool pattern::ConsiderMatch(uintptr_t offset)
{
const char* pattern = m_bytes.c_str();
const char* mask = m_mask.c_str();
bool pattern::ConsiderMatch(uintptr_t offset)
{
const uint8_t* pattern = m_bytes.data();
const uint8_t* mask = m_mask.data();
char* ptr = reinterpret_cast<char*>(offset);
char* ptr = reinterpret_cast<char*>(offset);
for (size_t i = 0, j = m_mask.size(); i < j; i++)
{
if (mask[i] == '?')
{
continue;
}
for (size_t i = 0; i < m_size; i++)
{
if ((pattern[i] & mask[i]) != (ptr[i] & mask[i]))
{
return false;
}
}
if (pattern[i] != ptr[i])
{
return false;
}
}
m_matches.emplace_back(ptr);
m_matches.emplace_back(ptr);
return true;
}
return true;
}
#if PATTERNS_USE_HINTS
void pattern::hint(uint64_t hash, uintptr_t address)
{
auto range = g_hints.equal_range(hash);
for (auto it = range.first; it != range.second; it++)
{
if (it->second == address)
{
return;
}
}
void InitializeHints()
{
static std::string modPath;
g_hints.emplace(hash, address);
}
if (modPath.empty())
{
char exeName[512];
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
char* exeBaseName = strrchr(exeName, '\\');
exeBaseName[0] = L'\0';
modPath = exeName;
modPath += "\\";
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
modPath = exeName;
modPath += "\\";
}
std::string hintsFile = modPath + "hints.dat";
FILE* hints = fopen(hintsFile.c_str(), "rb");
if (hints)
{
while (!feof(hints))
{
uint64_t hash;
uintptr_t hint;
fread(&hash, 1, sizeof(hash), hints);
fread(&hint, 1, sizeof(hint), hints);
hook::pattern::hint(hash, hint);
}
fclose(hints);
}
}
void pattern::hint(uint64_t hash, uintptr_t address)
{
auto range = GetHints().equal_range(hash);
for (auto it = range.first; it != range.second; it++)
{
if (it->second == address)
{
return;
}
}
GetHints().emplace(hash, address);
}
#endif
}

View File

@ -1,242 +1,201 @@
/*
* This file is part of the CitizenFX project - http://citizen.re/
*
* See LICENSE and MENTIONS in the root of the source tree for information
* regarding licensing.
*/
* This file is part of the CitizenFX project - http://citizen.re/
*
* See LICENSE and MENTIONS in the root of the source tree for information
* regarding licensing.
*/
#pragma once
#define PATTERNS_USE_HINTS 0
#include <cassert>
#include <vector>
#pragma warning(push)
#pragma warning(disable:4201)
#define PATTERNS_USE_HINTS 1
namespace hook
{
extern ptrdiff_t baseAddressDifference;
class pattern_match
{
private:
void* m_pointer;
// sets the base address difference based on an obtained pointer
inline void set_base(uintptr_t address)
{
#ifdef _M_IX86
uintptr_t addressDiff = (address - 0x400000);
#elif defined(_M_AMD64)
uintptr_t addressDiff = (address - 0x140000000);
#endif
public:
inline pattern_match(void* pointer)
: m_pointer(pointer)
{
}
// pointer-style cast to ensure unsigned overflow ends up copied directly into a signed value
baseAddressDifference = *(ptrdiff_t*)&addressDiff;
}
template<typename T>
T* get(ptrdiff_t offset = 0) const
{
char* ptr = reinterpret_cast<char*>(m_pointer);
return reinterpret_cast<T*>(ptr + offset);
}
};
// sets the base to the process main base
void set_base();
template<typename T>
inline T* getRVA(uintptr_t rva)
{
set_base();
#ifdef _M_IX86
return (T*)(baseAddressDifference + 0x400000 + rva);
#elif defined(_M_AMD64)
return (T*)(baseAddressDifference + 0x140000000 + rva);
#endif
}
class pattern_match
{
private:
void* m_pointer;
public:
inline pattern_match(void* pointer)
: m_pointer(pointer)
{
}
template<typename T>
T* get(ptrdiff_t offset = 0) const
{
char* ptr = reinterpret_cast<char*>(m_pointer);
return reinterpret_cast<T*>(ptr + offset);
}
};
class pattern
{
private:
std::vector<uint8_t> m_bytes;
std::vector<uint8_t> m_mask;
class pattern
{
private:
std::string m_bytes;
std::string m_mask;
#if PATTERNS_USE_HINTS
uint64_t m_hash;
uint64_t m_hash;
#endif
size_t m_size;
std::vector<pattern_match> m_matches;
std::vector<pattern_match> m_matches;
bool m_matched;
bool m_matched;
union
{
void* m_module;
struct
{
uintptr_t m_rangeStart;
uintptr_t m_rangeEnd;
};
};
union
{
void* m_module;
struct
{
uintptr_t m_rangeStart;
uintptr_t m_rangeEnd;
};
};
protected:
inline pattern(void* module)
: m_rangeStart((uintptr_t)module), m_matched(false), m_rangeEnd(0)
{
}
protected:
inline pattern(void* module)
: m_module(module), m_rangeEnd(0), m_matched(false)
{
}
inline pattern(uintptr_t begin, uintptr_t end)
: m_rangeStart(begin), m_rangeEnd(end), m_matched(false)
{
}
inline pattern(uintptr_t begin, uintptr_t end)
: m_rangeStart(begin), m_rangeEnd(end), m_matched(false)
{
}
void Initialize(const char* pattern, size_t length);
void Initialize(const char* pattern);
private:
bool ConsiderMatch(uintptr_t offset);
private:
bool ConsiderMatch(uintptr_t offset);
void EnsureMatches(uint32_t maxCount);
void EnsureMatches(uint32_t maxCount);
inline pattern_match _get_internal(size_t index) const
{
return m_matches[index];
}
inline const pattern_match& _get_internal(size_t index)
{
return m_matches[index];
}
public:
template<size_t Len>
pattern(const char(&pattern)[Len])
: pattern(GetModuleHandle(NULL))
{
Initialize(pattern, Len);
}
public:
pattern()
: m_matched(true)
{
}
inline pattern& count(uint32_t expected) &
{
EnsureMatches(expected);
assert(m_matches.size() == expected);
return *this;
}
pattern(const char *pattern)
: pattern(getRVA<void>(0))
{
Initialize(pattern);
}
inline pattern& count_hint(uint32_t expected) &
{
EnsureMatches(expected);
return *this;
}
pattern(std::string& pattern)
: pattern(getRVA<void>(0))
{
Initialize(pattern.c_str());
}
inline pattern& clear() &
{
m_matches.clear();
m_matched = false;
return *this;
}
inline pattern& count(uint32_t expected)
{
EnsureMatches(expected);
assert(m_matches.size() == expected);
return *this;
}
inline pattern&& count(uint32_t expected) &&
{
EnsureMatches(expected);
assert(m_matches.size() == expected);
return std::move(*this);
}
inline pattern& count_hint(uint32_t expected)
{
EnsureMatches(expected);
return *this;
}
inline pattern&& count_hint(uint32_t expected) &&
{
EnsureMatches(expected);
return std::move(*this);
}
inline pattern& clear(void* module = nullptr)
{
if (module)
m_module = module;
m_matches.clear();
m_matched = false;
return *this;
}
inline pattern&& clear() &&
{
m_matches.clear();
m_matched = false;
return std::move(*this);
}
inline size_t size()
{
EnsureMatches(UINT32_MAX);
return m_matches.size();
}
inline size_t size()
{
EnsureMatches(UINT32_MAX);
return m_matches.size();
}
inline bool empty()
{
return size() == 0;
}
inline bool empty()
{
return size() == 0;
}
inline const pattern_match& get(size_t index)
{
EnsureMatches(UINT32_MAX);
return _get_internal(index);
}
inline pattern_match get(size_t index)
{
EnsureMatches(UINT32_MAX);
return _get_internal(index);
}
inline const pattern_match& get_one()
{
return count(1)._get_internal(0);
}
inline pattern_match get_one()
{
return std::forward<pattern>(*this).count(1)._get_internal(0);
}
template<typename T = void>
inline auto get_first(ptrdiff_t offset = 0)
{
return get_one().get<T>(offset);
}
template<typename T = void>
inline auto get_first(ptrdiff_t offset = 0)
{
return get_one().get<T>(offset);
}
template <typename Fn>
pattern &for_each_result(Fn Pr)
{
EnsureMatches(UINT32_MAX);
for (auto &result : this->m_matches)
{
Pr(result);
}
return *this;
}
public:
public:
#if PATTERNS_USE_HINTS
// define a hint
static void hint(uint64_t hash, uintptr_t address);
// define a hint
static void hint(uint64_t hash, uintptr_t address);
#endif
};
};
class module_pattern
: public pattern
{
public:
module_pattern(void* module, const char *pattern)
: pattern(module)
{
Initialize(pattern);
}
class module_pattern
: public pattern
{
public:
template<size_t Len>
module_pattern(void* module, const char(&pattern)[Len])
: pattern(module)
{
Initialize(pattern, Len);
}
};
module_pattern(void* module, std::string& pattern)
: pattern(module)
{
Initialize(pattern.c_str());
}
};
class range_pattern
: public pattern
{
public:
range_pattern(uintptr_t begin, uintptr_t end, const char *pattern)
: pattern(begin, end)
{
Initialize(pattern);
}
range_pattern(uintptr_t begin, uintptr_t end, std::string& pattern)
: pattern(begin, end)
{
Initialize(pattern.c_str());
}
};
class range_pattern
: public pattern
{
public:
template<size_t Len>
range_pattern(uintptr_t begin, uintptr_t end, const char(&pattern)[Len])
: pattern(begin, end)
{
Initialize(pattern, Len);
}
};
template<typename T = void>
auto get_pattern(const char *pattern_string, ptrdiff_t offset = 0)
{
return pattern(pattern_string).get_first<T>(offset);
}
template<typename T = void, size_t Len>
auto get_pattern(const char(&pattern_string)[Len], ptrdiff_t offset = 0)
{
return pattern(pattern_string).get_first<T>(offset);
}
}
#pragma warning(pop)

View File

@ -23,8 +23,8 @@ project "iDmacDrv"
filter "platforms:x86"
targetsuffix "32"
linkoptions { "/DEF:iDmacDrv/src/Source32.def" }
linkoptions { "/DEF:$(ProjectDir)/src/Source32.def" }
filter "platforms:x64"
targetsuffix "64"
linkoptions { "/DEF:iDmacDrv/src/Source64.def" }
linkoptions { "/DEF:$(ProjectDir)/src/Source64.def" }

View File

@ -1,2 +1 @@
premake5 vs2017
pause
premake5 vs2019

Binary file not shown.

View File

@ -4,7 +4,7 @@ workspace "OpenParrot"
flags { "StaticRuntime", "No64BitChecks" }
systemversion "10.0.16299.0"
systemversion "latest"
symbols "On"