Add initial working wrapper
This commit is contained in:
parent
4b05449c7c
commit
da918e59da
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="'$(SolutionDir)'==''">..\..\</SolutionDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Allow any version of VS and Windows SDK -->
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
|
||||
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DisableSpecificWarnings>4068;4091;4100;4132;4200;4201;4204;4206;4221;4244;4245;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<!-- Warnings:
|
||||
C4068: unknown pragma
|
||||
C4091: 'keyword': ignored on left of 'type' when no variable is declared
|
||||
C4100: 'identifier': unreferenced formal parameter
|
||||
C4132: 'identifier': const object should be initialized
|
||||
C4200: nonstandard extension used: zero-sized array in struct/union
|
||||
C4201: nonstandard extension used: nameless struct/union
|
||||
C4204: nonstandard extension used: non-constant aggregate initializer
|
||||
C4206: nonstandard extension used: translation unit is empty
|
||||
C4221: nonstandard extension used: 'identifier': cannot be initialized using address of automatic variable 'identifier'
|
||||
C4244: 'conversion_type': conversion from 'type1' to 'type2', possible loss of data
|
||||
C4245: 'conversion_type': conversion from 'type1' to 'type2', signed/unsigned mismatch
|
||||
-->
|
||||
<TreatSpecificWarningsAsErrors>4263;4265;4548;4549;4555</TreatSpecificWarningsAsErrors>
|
||||
<!-- Warnings, that have to be enabled manually:
|
||||
C4263: 'function': member function does not override any base class virtual member function
|
||||
C4265: 'class': class has virtual functions, but destructor is not virtual
|
||||
C4548: expression before comma has no effect; expected expression with side-effect
|
||||
C4549: 'operator': operator before comma has no effect; did you intend 'operator'?
|
||||
C4555: expression has no effect; expected expression with side-effect
|
||||
-->
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalOptions>/utf-8 /std:c++latest /permissive-</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>imm32.lib;version.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/OPT:NOLBR /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration>UseFastLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>Full</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck />
|
||||
<OmitFramePointers />
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<IncludePath>$(SolutionDir)src;$(SolutionDir)lib\include;$(SolutionDir)lib\include\sdl2;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
|
||||
<LinkIncremental />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2010
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openloco", "src\openloco\openloco.vcxproj", "{42A6B551-4EC5-4B66-A130-628622CD98C4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D35A17D9-494B-43DB-8008-B47DC58227DD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{42A6B551-4EC5-4B66-A130-628622CD98C4}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{42A6B551-4EC5-4B66-A130-628622CD98C4}.Debug|x86.Build.0 = Debug|Win32
|
||||
{42A6B551-4EC5-4B66-A130-628622CD98C4}.Release|x86.ActiveCfg = Release|Win32
|
||||
{42A6B551-4EC5-4B66-A130-628622CD98C4}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{42A6B551-4EC5-4B66-A130-628622CD98C4} = {D35A17D9-494B-43DB-8008-B47DC58227DD}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DBA01ADD-F7E5-4C06-AA84-168F663E5A81}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,266 @@
|
|||
#include <memory>
|
||||
#include "interop.hpp"
|
||||
|
||||
registers::registers()
|
||||
{
|
||||
// We set registers to known undefined values so we are easily aware when
|
||||
// code is attempting to use undefined registers.
|
||||
std::memset(this, 0xCC, sizeof(registers));
|
||||
}
|
||||
|
||||
#pragma warning(disable : 4731) // frame pointer register 'ebp' modified by inline assembly code
|
||||
#define PLATFORM_X86
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#ifdef __clang__
|
||||
#define DISABLE_OPT __attribute__((noinline,optnone))
|
||||
#else
|
||||
#define DISABLE_OPT __attribute__((noinline,optimize("O0")))
|
||||
#endif // __clang__
|
||||
#else
|
||||
#define DISABLE_OPT
|
||||
#endif // defined(__GNUC__)
|
||||
|
||||
// This variable serves a purpose of identifying a crash if it has happened inside original code.
|
||||
// When switching to original code, stack frame pointer is modified and prevents breakpad from providing stack trace.
|
||||
volatile int32_t _originalAddress = 0;
|
||||
|
||||
int32_t DISABLE_OPT LOCO_CALLPROC_X(int32_t address, int32_t _eax, int32_t _ebx, int32_t _ecx, int32_t _edx, int32_t _esi, int32_t _edi, int32_t _ebp)
|
||||
{
|
||||
int32_t result = 0;
|
||||
_originalAddress = address;
|
||||
#if defined(PLATFORM_X86)
|
||||
#ifdef _MSC_VER
|
||||
__asm {
|
||||
push ebp
|
||||
push address
|
||||
mov eax, _eax
|
||||
mov ebx, _ebx
|
||||
mov ecx, _ecx
|
||||
mov edx, _edx
|
||||
mov esi, _esi
|
||||
mov edi, _edi
|
||||
mov ebp, _ebp
|
||||
call[esp]
|
||||
lahf
|
||||
pop ebp
|
||||
pop ebp
|
||||
/* Load result with flags */
|
||||
mov result, eax
|
||||
}
|
||||
#else
|
||||
__asm__ volatile ("\
|
||||
\n\
|
||||
push %%ebx \n\
|
||||
push %%ebp \n\
|
||||
push %[address] \n\
|
||||
mov %[eax], %%eax \n\
|
||||
mov %[ebx], %%ebx \n\
|
||||
mov %[ecx], %%ecx \n\
|
||||
mov %[edx], %%edx \n\
|
||||
mov %[esi], %%esi \n\
|
||||
mov %[edi], %%edi \n\
|
||||
mov %[ebp], %%ebp \n\
|
||||
call *(%%esp) \n\
|
||||
lahf \n\
|
||||
add $4, %%esp \n\
|
||||
pop %%ebp \n\
|
||||
pop %%ebx \n\
|
||||
/* Load result with flags */ \n\
|
||||
mov %%eax, %[result] \n\
|
||||
" : [address] "+m" (address), [eax] "+m" (_eax), [ebx] "+m" (_ebx), [ecx] "+m" (_ecx), [edx] "+m" (_edx), [esi] "+m" (_esi), [edi] "+m" (_edi), [ebp] "+m" (_ebp), [result] "+m" (result)
|
||||
:
|
||||
: "eax", "ecx", "edx", "esi", "edi", "memory"
|
||||
);
|
||||
#endif
|
||||
#endif // PLATFORM_X86
|
||||
_originalAddress = 0;
|
||||
// lahf only modifies ah, zero out the rest
|
||||
return result & 0xFF00;
|
||||
}
|
||||
|
||||
int32_t DISABLE_OPT LOCO_CALLFUNC_X(int32_t address, int32_t *_eax, int32_t *_ebx, int32_t *_ecx, int32_t *_edx, int32_t *_esi, int32_t *_edi, int32_t *_ebp)
|
||||
{
|
||||
int32_t result = 0;
|
||||
_originalAddress = address;
|
||||
#if defined(PLATFORM_X86)
|
||||
#ifdef _MSC_VER
|
||||
__asm {
|
||||
// Store C's base pointer
|
||||
push ebp
|
||||
push ebx
|
||||
// Store address to call
|
||||
push address
|
||||
|
||||
// Set all registers to the input values
|
||||
mov eax, [_eax]
|
||||
mov eax, [eax]
|
||||
mov ebx, [_ebx]
|
||||
mov ebx, [ebx]
|
||||
mov ecx, [_ecx]
|
||||
mov ecx, [ecx]
|
||||
mov edx, [_edx]
|
||||
mov edx, [edx]
|
||||
mov esi, [_esi]
|
||||
mov esi, [esi]
|
||||
mov edi, [_edi]
|
||||
mov edi, [edi]
|
||||
mov ebp, [_ebp]
|
||||
mov ebp, [ebp]
|
||||
|
||||
// Call function
|
||||
call[esp]
|
||||
|
||||
// Store output eax
|
||||
push eax
|
||||
push ebp
|
||||
push ebx
|
||||
mov ebp, [esp + 20]
|
||||
mov ebx, [esp + 16]
|
||||
|
||||
// Get resulting ecx, edx, esi, edi registers
|
||||
|
||||
mov eax, [_edi]
|
||||
mov[eax], edi
|
||||
mov eax, [_esi]
|
||||
mov[eax], esi
|
||||
mov eax, [_edx]
|
||||
mov[eax], edx
|
||||
mov eax, [_ecx]
|
||||
mov[eax], ecx
|
||||
|
||||
// Pop ebx reg into ecx
|
||||
pop ecx
|
||||
mov eax, [_ebx]
|
||||
mov[eax], ecx
|
||||
|
||||
// Pop ebp reg into ecx
|
||||
pop ecx
|
||||
mov eax, [_ebp]
|
||||
mov[eax], ecx
|
||||
|
||||
pop eax
|
||||
// Get resulting eax register
|
||||
mov ecx, [_eax]
|
||||
mov[ecx], eax
|
||||
|
||||
// Save flags as return in eax
|
||||
lahf
|
||||
// Pop address
|
||||
pop ebp
|
||||
|
||||
pop ebx
|
||||
pop ebp
|
||||
/* Load result with flags */
|
||||
mov result, eax
|
||||
}
|
||||
#else
|
||||
__asm__ volatile ("\
|
||||
\n\
|
||||
/* Store C's base pointer*/ \n\
|
||||
push %%ebp \n\
|
||||
push %%ebx \n\
|
||||
\n\
|
||||
/* Store %[address] to call*/ \n\
|
||||
push %[address] \n\
|
||||
\n\
|
||||
/* Set all registers to the input values*/ \n\
|
||||
mov %[_eax], %%eax \n\
|
||||
mov (%%eax), %%eax \n\
|
||||
mov %[_ebx], %%ebx \n\
|
||||
mov (%%ebx), %%ebx \n\
|
||||
mov %[_ecx], %%ecx \n\
|
||||
mov (%%ecx), %%ecx \n\
|
||||
mov %[_edx], %%edx \n\
|
||||
mov (%%edx), %%edx \n\
|
||||
mov %[_esi], %%esi \n\
|
||||
mov (%%esi), %%esi \n\
|
||||
mov %[_edi], %%edi \n\
|
||||
mov (%%edi), %%edi \n\
|
||||
mov %[_ebp], %%ebp \n\
|
||||
mov (%%ebp), %%ebp \n\
|
||||
\n\
|
||||
/* Call function*/ \n\
|
||||
call *(%%esp) \n\
|
||||
\n\
|
||||
/* Store output eax */ \n\
|
||||
push %%eax \n\
|
||||
push %%ebp \n\
|
||||
push %%ebx \n\
|
||||
mov 20(%%esp), %%ebp \n\
|
||||
mov 16(%%esp), %%ebx \n\
|
||||
/* Get resulting ecx, edx, esi, edi registers*/ \n\
|
||||
mov %[_edi], %%eax \n\
|
||||
mov %%edi, (%%eax) \n\
|
||||
mov %[_esi], %%eax \n\
|
||||
mov %%esi, (%%eax) \n\
|
||||
mov %[_edx], %%eax \n\
|
||||
mov %%edx, (%%eax) \n\
|
||||
mov %[_ecx], %%eax \n\
|
||||
mov %%ecx, (%%eax) \n\
|
||||
/* Pop ebx reg into ecx*/ \n\
|
||||
pop %%ecx \n\
|
||||
mov %[_ebx], %%eax \n\
|
||||
mov %%ecx, (%%eax) \n\
|
||||
\n\
|
||||
/* Pop ebp reg into ecx */\n\
|
||||
pop %%ecx \n\
|
||||
mov %[_ebp], %%eax \n\
|
||||
mov %%ecx, (%%eax) \n\
|
||||
\n\
|
||||
pop %%eax \n\
|
||||
/* Get resulting eax register*/ \n\
|
||||
mov %[_eax], %%ecx \n\
|
||||
mov %%eax, (%%ecx) \n\
|
||||
\n\
|
||||
/* Save flags as return in eax*/ \n\
|
||||
lahf \n\
|
||||
/* Pop address*/ \n\
|
||||
pop %%ebp \n\
|
||||
\n\
|
||||
pop %%ebx \n\
|
||||
pop %%ebp \n\
|
||||
/* Load result with flags */ \n\
|
||||
mov %%eax, %[result] \n\
|
||||
" : [address] "+m" (address), [_eax] "+m" (_eax), [_ebx] "+m" (_ebx), [_ecx] "+m" (_ecx), [_edx] "+m" (_edx), [_esi] "+m" (_esi), [_edi] "+m" (_edi), [_ebp] "+m" (_ebp), [result] "+m" (result)
|
||||
|
||||
:
|
||||
: "eax", "ecx", "edx", "esi", "edi", "memory"
|
||||
);
|
||||
#endif
|
||||
#endif // PLATFORM_X86
|
||||
_originalAddress = 0;
|
||||
// lahf only modifies ah, zero out the rest
|
||||
return result & 0xFF00;
|
||||
}
|
||||
|
||||
int32_t LOCO_CALLPROC_X(int32_t address, const registers ®isters)
|
||||
{
|
||||
return LOCO_CALLPROC_X(
|
||||
address,
|
||||
registers.eax,
|
||||
registers.ebx,
|
||||
registers.ecx,
|
||||
registers.edx,
|
||||
registers.esi,
|
||||
registers.edi,
|
||||
registers.ebp);
|
||||
}
|
||||
|
||||
int32_t LOCO_CALLPROC_X(int32_t address)
|
||||
{
|
||||
return LOCO_CALLPROC_X(address, registers());
|
||||
}
|
||||
|
||||
int32_t LOCO_CALLFUNC_X(int32_t address, registers ®isters)
|
||||
{
|
||||
return LOCO_CALLFUNC_X(
|
||||
address,
|
||||
®isters.eax,
|
||||
®isters.ebx,
|
||||
®isters.ecx,
|
||||
®isters.edx,
|
||||
®isters.esi,
|
||||
®isters.edi,
|
||||
®isters.ebp);
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define assert_struct_size(x, y) static_assert(sizeof(x) == (y), "Improper struct size")
|
||||
|
||||
/**
|
||||
* x86 register structure, only used for easy interop to Locomotion code.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
struct registers
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t eax;
|
||||
int16_t ax;
|
||||
struct
|
||||
{
|
||||
int8_t al;
|
||||
int8_t ah;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebx;
|
||||
int16_t bx;
|
||||
struct
|
||||
{
|
||||
int8_t bl;
|
||||
int8_t bh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ecx;
|
||||
int16_t cx;
|
||||
struct
|
||||
{
|
||||
int8_t cl;
|
||||
int8_t ch;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edx;
|
||||
int16_t dx;
|
||||
struct
|
||||
{
|
||||
int8_t dl;
|
||||
int8_t dh;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t esi;
|
||||
int16_t si;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t edi;
|
||||
int16_t di;
|
||||
};
|
||||
union
|
||||
{
|
||||
int32_t ebp;
|
||||
int16_t bp;
|
||||
};
|
||||
|
||||
registers();
|
||||
};
|
||||
assert_struct_size(registers, 7 * 4);
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#if defined(PLATFORM_64BIT)
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x200000000)
|
||||
#elif defined(PLATFORM_32BIT)
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x09000000)
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
#else
|
||||
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x8A4000)
|
||||
#endif
|
||||
|
||||
#define LOCO_ADDRESS(address, type) ((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8A4000 + (address)))
|
||||
#define LOCO_GLOBAL(address, type) (*((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8A4000 + (address))))
|
||||
|
||||
/**
|
||||
* Returns the flags register
|
||||
*
|
||||
* Flags register is as follows:
|
||||
* 0bSZ0A_0P0C_0000_0000
|
||||
* S = Signed flag
|
||||
* Z = Zero flag
|
||||
* C = Carry flag
|
||||
* A = Adjust flag
|
||||
* P = Parity flag
|
||||
* All other bits are undefined.
|
||||
*/
|
||||
int32_t LOCO_CALLPROC_X(int32_t address, int32_t _eax, int32_t _ebx, int32_t _ecx, int32_t _edx, int32_t _esi, int32_t _edi, int32_t _ebp);
|
||||
int32_t LOCO_CALLPROC_X(int32_t address, const registers ®isters);
|
||||
int32_t LOCO_CALLPROC_X(int32_t address);
|
||||
|
||||
/**
|
||||
* Returns the flags register
|
||||
*
|
||||
* Flags register is as follows:
|
||||
* 0bSZ0A_0P0C_0000_00000
|
||||
* S = Signed flag
|
||||
* Z = Zero flag
|
||||
* C = Carry flag
|
||||
* A = Adjust flag
|
||||
* P = Parity flag
|
||||
* All other bits are undefined.
|
||||
*/
|
||||
int32_t LOCO_CALLFUNC_X(int32_t address, int32_t *_eax, int32_t *_ebx, int32_t *_ecx, int32_t *_edx, int32_t *_esi, int32_t *_edi, int32_t *_ebp);
|
||||
int32_t LOCO_CALLFUNC_X(int32_t address, registers ®isters);
|
||||
|
||||
template<typename T, uint32_t TAddress>
|
||||
struct loco_global
|
||||
{
|
||||
void operator=(T rhs)
|
||||
{
|
||||
LOCO_GLOBAL(TAddress, T) = rhs;
|
||||
}
|
||||
|
||||
operator T()
|
||||
{
|
||||
return LOCO_GLOBAL(TAddress, T);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,111 @@
|
|||
#include <string>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "interop\interop.hpp"
|
||||
|
||||
namespace openloco
|
||||
{
|
||||
constexpr auto WINDOW_CLASS_NAME = "Chris Sawyer's Locomotion";
|
||||
constexpr auto WINDOW_TITLE = "OpenLoco";
|
||||
|
||||
loco_global<HINSTANCE, 0x0113E0B4> ghInstance;
|
||||
loco_global<LPSTR, 0x00525348> glpCmdLine;
|
||||
loco_global<HWND, 0x00525320> gMainHWND;
|
||||
|
||||
// 0x00405409
|
||||
HWND create_game_window()
|
||||
{
|
||||
return CreateWindowExA(
|
||||
WS_EX_TOPMOST,
|
||||
WINDOW_CLASS_NAME,
|
||||
WINDOW_TITLE,
|
||||
WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_CLIPCHILDREN | WS_MAXIMIZE | WS_CLIPSIBLINGS,
|
||||
0,
|
||||
0,
|
||||
GetSystemMetrics(SM_CXSCREEN),
|
||||
GetSystemMetrics(SM_CYSCREEN),
|
||||
nullptr,
|
||||
nullptr,
|
||||
ghInstance,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
bool sub_4054B9()
|
||||
{
|
||||
registers regs;
|
||||
LOCO_CALLFUNC_X(0x004054B9, regs);
|
||||
return regs.eax != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to allocate memory that will be freed in vanilla code or via loco_free.
|
||||
*/
|
||||
void * malloc(size_t size)
|
||||
{
|
||||
return ((void *(*)(size_t))0x004D1401)(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to reallocate memory that will be freed in vanilla code or via loco_free.
|
||||
*/
|
||||
void * realloc(void * address, size_t size)
|
||||
{
|
||||
return ((void *(*)(void *, size_t))0x004D1B28)(address, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to free up memory allocated in vanilla code or via loco_malloc / loco_realloc.
|
||||
*/
|
||||
void free(void * address)
|
||||
{
|
||||
((void(*)(void *))0x004D1355)(address);
|
||||
}
|
||||
|
||||
void sub_404E58()
|
||||
{
|
||||
free(LOCO_GLOBAL(0x005251F4, void *));
|
||||
LOCO_GLOBAL(0x005251F4, void *) = nullptr;
|
||||
LOCO_GLOBAL(0x005251F0, void *) = nullptr;
|
||||
LOCO_CALLPROC_X(0x00404ACD);
|
||||
LOCO_CALLPROC_X(0x00404B40);
|
||||
}
|
||||
|
||||
// 0x00406386
|
||||
void openloco_run()
|
||||
{
|
||||
LOCO_CALLPROC_X(0x00406386);
|
||||
}
|
||||
|
||||
// 0x00406D13
|
||||
void main()
|
||||
{
|
||||
if (sub_4054B9())
|
||||
{
|
||||
gMainHWND = create_game_window();
|
||||
LOCO_CALLPROC_X(0x004078FE);
|
||||
LOCO_CALLPROC_X(0x00407B26);
|
||||
LOCO_CALLPROC_X(0x0040447F);
|
||||
LOCO_CALLPROC_X(0x00404E53);
|
||||
openloco_run();
|
||||
LOCO_CALLPROC_X(0x00404E58);
|
||||
LOCO_CALLPROC_X(0x004045C2);
|
||||
|
||||
// TODO extra clean up code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/**
|
||||
* The function that is called directly from the host application (loco.exe)'s WinMain. This will be removed when OpenLoco can
|
||||
* be built as a stand alone application.
|
||||
*/
|
||||
__declspec(dllexport) int StartOpenLoco(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
openloco::glpCmdLine = lpCmdLine;
|
||||
openloco::ghInstance = hInstance;
|
||||
openloco::main();
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="'$(SolutionDir)'==''">..\..\</SolutionDir>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="interop\interop.cpp" />
|
||||
<ClCompile Include="openloco.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="interop\interop.hpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{42A6B551-4EC5-4B66-A130-628622CD98C4}</ProjectGuid>
|
||||
<RootNamespace>openloco</RootNamespace>
|
||||
<ProjectName>openloco</ProjectName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\openloco.common.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<ObjectFileName>$(IntDir)\%(RelativeDir)</ObjectFileName>
|
||||
<AdditionalOptions>$(OPENLOCO_CL_ADDITIONALOPTIONS) %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<TargetMachine Condition="'$(Platform)'=='Win32'">MachineX86</TargetMachine>
|
||||
<TargetMachine Condition="'$(Platform)'=='x64'">MachineX64</TargetMachine>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
Loading…
Reference in New Issue