This commit is contained in:
itsmattkc 2021-11-02 17:03:02 -07:00
commit d4b2bd04e9
11 changed files with 460 additions and 45 deletions

View file

@ -5,8 +5,6 @@ project(Rebuilder LANGUAGES CXX)
set(CMAKE_MFC_FLAG 2)
add_compile_definitions(_AFXDLL)
option(BUILD_UNICODE "Build with Unicode support" ON)
#
# Build our code injected DLL
#
@ -51,12 +49,6 @@ add_executable(Rebuilder WIN32
src/window.h
)
if (BUILD_UNICODE)
target_compile_definitions(Rebuilder PRIVATE UNICODE _UNICODE)
target_compile_definitions(Rebld PRIVATE UNICODE _UNICODE)
target_link_options(Rebuilder PRIVATE /entry:wWinMainCRTStartup)
endif()
target_link_libraries(Rebuilder PRIVATE shlwapi.lib PropertyGrid)
# Ensure DLL is compiled before resource is built into executable

View file

@ -1,6 +1,8 @@
#include "config.h"
#include <SHLWAPI.H>
#include <SSTREAM>
#include <STRING>
#include "../cmn/path.h"
@ -22,3 +24,29 @@ UINT Config::GetInt(LPCTSTR name, UINT defaultValue)
{
return GetPrivateProfileInt(appName, name, defaultValue, m_configFile.c_str());
}
float Config::GetFloat(LPCTSTR name, float defaultValue)
{
// Convert float to string
std::ostringstream oss;
oss << defaultValue;
std::string defaultStr = oss.str();
std::string currentStr = GetString(name, defaultStr);
// Convert to float
return atof(currentStr.c_str());
}
std::string Config::GetString(LPCTSTR name, const std::string &defaultValue)
{
const int max_string_sz = 100;
std::string s;
s.resize(max_string_sz);
DWORD count = GetPrivateProfileString(appName, name, defaultValue.c_str(), &s[0], max_string_sz, m_configFile.c_str());
s.resize(count);
return s;
}

View file

@ -14,6 +14,10 @@ public:
UINT GetInt(LPCTSTR name, UINT defaultValue = 0);
float GetFloat(LPCTSTR name, float defaultValue = 0.0f);
std::string GetString(LPCTSTR name, const std::string &defaultValue = std::string());
private:
std::basic_string<TCHAR> m_configFile;

View file

@ -1,5 +1,6 @@
#include "hooks.h"
#include <MATH.H>
#include <STDIO.H>
#include "../cmn/path.h"
@ -53,7 +54,7 @@ HRESULT WINAPI InterceptSurfaceGetDesc(LPDIRECTDRAWSURFACE lpDDSurface, LPDDSURF
HRESULT res = originalDDSurfaceGetDescFunction(lpDDSurface, lpDDSurfaceDesc);
if (res == DD_OK) {
ForceDDSurfaceDescTo16(lpDDSurfaceDesc);
//ForceDDSurfaceDescTo16(lpDDSurfaceDesc);
}
return res;
@ -172,9 +173,213 @@ LONG WINAPI InterceptRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpR
// Pass through
} else {
MessageBoxA(isleWindow, lpValueName, "ISLE asked for...", 0);
printf("Passed through requested registry key \"%s\"\n", lpValueName);
}
// Pass these through
return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
}
void WINAPI InterceptSleep(DWORD dwMilliseconds)
{
// Do nothing
std::string fps_behavior = config.GetString(_T("FPSLimit"));
// If uncapped, do nothing
if (fps_behavior != "Uncapped") {
// If not default, pass through new FPS
if (fps_behavior == "Limited") {
dwMilliseconds = 1000.0f / config.GetFloat(_T("CustomFPS"));
}
Sleep(dwMilliseconds);
}
}
LPDIRECT3DRMVIEWPORT last_viewport = NULL;
D3DVALUE last_fov = 0.0f;
typedef HRESULT (WINAPI *d3drmViewportSetFieldFunction)(LPDIRECT3DRMVIEWPORT viewport, D3DVALUE field);
d3drmViewportSetFieldFunction d3drmViewportSetFieldOriginal = NULL;
HRESULT WINAPI InterceptD3DRMViewportSetField(LPDIRECT3DRMVIEWPORT viewport, D3DVALUE field)
{
last_viewport = viewport;
last_fov = field;
return d3drmViewportSetFieldOriginal(viewport, field);
}
typedef HRESULT (WINAPI *d3drmCreateViewportFunction)(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport);
d3drmCreateViewportFunction d3drmCreateViewportOriginal = NULL;
HRESULT WINAPI InterceptD3DRMCreateViewport(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport)
{
HRESULT res = d3drmCreateViewportOriginal(d3drm, device, frame, x, y, w, h, viewport);
if (res == DD_OK) {
if (!d3drmViewportSetFieldOriginal) {
d3drmViewportSetFieldOriginal = (d3drmViewportSetFieldFunction)OverwriteVirtualTable(*viewport, 0x10, (LPVOID)InterceptD3DRMViewportSetField);
}
}
return res;
}
d3drmCreateFunction d3drmCreateOriginal = NULL;
HRESULT WINAPI InterceptDirect3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM)
{
HRESULT result = d3drmCreateOriginal(lplpDirect3DRM);
if (result == DD_OK) {
if (!d3drmCreateViewportOriginal) {
d3drmCreateViewportOriginal = (d3drmCreateViewportFunction)OverwriteVirtualTable(*lplpDirect3DRM, 0x38, (LPVOID)InterceptD3DRMCreateViewport);
}
}
return result;
}
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0x020A
#endif
#ifndef WHEEL_DELTA
#define WHEEL_DELTA 120
#endif
WNDPROC originalWndProc = NULL;
LRESULT CALLBACK InterceptWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_MOUSEWHEEL) {
SHORT distance = HIWORD(wParam);
distance /= WHEEL_DELTA;
float multiplier = 0.005 * distance;
InterceptD3DRMViewportSetField(last_viewport, last_fov + multiplier);
return 0;
}
return originalWndProc(hwnd, uMsg, wParam, lParam);
}
ATOM WINAPI InterceptRegisterClassA(const WNDCLASSA *c)
{
WNDCLASSA copy = *c;
originalWndProc = copy.lpfnWndProc;
copy.lpfnWndProc = InterceptWindowProc;
return RegisterClassA(&copy);
}
typedef HRESULT (WINAPI *dsCreateSoundBufferFunction)(LPDIRECTSOUND lpDS, LPCDSBUFFERDESC desc, LPDIRECTSOUNDBUFFER *buffer, LPUNKNOWN unk);
dsCreateSoundBufferFunction dsCreateSoundBufferOriginal = NULL;
HRESULT WINAPI InterceptDirectSoundCreateSoundBuffer(LPDIRECTSOUND lpDS, LPCDSBUFFERDESC desc, LPDIRECTSOUNDBUFFER *buffer, LPUNKNOWN unk)
{
DSBUFFERDESC copy = *desc;
if (config.GetInt(_T("StayActiveWhenDefocused")) && !(copy.dwFlags & DSBCAPS_PRIMARYBUFFER)) {
copy.dwFlags |= DSBCAPS_GLOBALFOCUS;
}
return dsCreateSoundBufferOriginal(lpDS, &copy, buffer, unk);
}
dsCreateFunction dsCreateOriginal = NULL;
HRESULT WINAPI InterceptDirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter )
{
HRESULT res = dsCreateOriginal(lpGuid, ppDS, pUnkOuter);
if (res == DD_OK) {
if (!dsCreateSoundBufferOriginal) {
dsCreateSoundBufferOriginal = (dsCreateSoundBufferFunction)OverwriteVirtualTable(*ppDS, 0x3, (LPVOID)InterceptDirectSoundCreateSoundBuffer);
}
}
return res;
}
SHORT WINAPI InterceptGetAsyncKeyState(int vKey)
{
if (config.GetInt("UseWASD")) {
switch (vKey) {
case VK_UP:
vKey = 'W';
break;
case VK_LEFT:
vKey = 'A';
break;
case VK_DOWN:
vKey = 'S';
break;
case VK_RIGHT:
vKey = 'D';
break;
case 'W':
vKey = VK_UP;
break;
case 'A':
vKey = VK_LEFT;
break;
case 'S':
vKey = VK_DOWN;
break;
case 'D':
vKey = VK_RIGHT;
break;
}
}
return GetAsyncKeyState(vKey);
}
typedef HRESULT (WINAPI *dinputGetDeviceStateFunction)(LPDIRECTINPUTDEVICEA lpDevice, DWORD cbData, LPVOID lpvData);
dinputGetDeviceStateFunction dinputGetDeviceStateOriginal = NULL;
HRESULT WINAPI InterceptDirectInputGetDeviceStateA(LPDIRECTINPUTDEVICEA lpDevice, DWORD cbData, LPVOID lpvData)
{
HRESULT res = dinputGetDeviceStateOriginal(lpDevice, cbData, lpvData);
if (config.GetInt("UseWASD") && res == DD_OK) {
if (cbData == 256) {
unsigned char *keys = (unsigned char *)lpvData;
// Swap state of WASD with arrow keys
std::swap(keys[DIK_W], keys[DIK_UP]);
std::swap(keys[DIK_A], keys[DIK_LEFT]);
std::swap(keys[DIK_S], keys[DIK_DOWN]);
std::swap(keys[DIK_D], keys[DIK_RIGHT]);
}
}
return res;
}
typedef HRESULT (WINAPI *dinputCreateDeviceFunction)(LPDIRECTINPUTA lpDI, REFGUID, LPDIRECTINPUTDEVICEA *, LPUNKNOWN);
dinputCreateDeviceFunction dinputCreateDeviceOriginal = NULL;
HRESULT WINAPI InterceptDirectInputCreateDeviceA(LPDIRECTINPUTA lpDI, REFGUID guid, LPDIRECTINPUTDEVICEA *ppDevice, LPUNKNOWN unk)
{
HRESULT res = dinputCreateDeviceOriginal(lpDI, guid, ppDevice, unk);
if (res == DD_OK) {
if (!dinputGetDeviceStateOriginal) {
dinputGetDeviceStateOriginal = (dinputGetDeviceStateFunction)OverwriteVirtualTable(*ppDevice, 0x9, (LPVOID)InterceptDirectInputGetDeviceStateA);
}
}
return res;
}
dinputCreateFunction dinputCreateOriginal = NULL;
HRESULT WINAPI InterceptDirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
{
HRESULT res = dinputCreateOriginal(hinst, dwVersion, ppDI, punkOuter);
if (res == DD_OK) {
if (!dinputCreateDeviceOriginal) {
dinputCreateDeviceOriginal = (dinputCreateDeviceFunction)OverwriteVirtualTable(*ppDI, 0x3, (LPVOID)InterceptDirectInputCreateDeviceA);
}
}
return res;
}

View file

@ -1,7 +1,10 @@
#ifndef HOOKS_H
#define HOOKS_H
#include <D3DRM.H>
#include <DDRAW.H>
#include <DINPUT.H>
#include <DSOUND.H>
#include <WINDOWS.H>
void InterceptOutputDebugStringA(LPCSTR s);
@ -21,6 +24,8 @@ HWND WINAPI InterceptCreateWindowExA(
LPVOID lpParam
);
LONG
APIENTRY
InterceptRegQueryValueExA (
@ -32,6 +37,8 @@ InterceptRegQueryValueExA (
LPDWORD lpcbData
);
ATOM WINAPI InterceptRegisterClassA(const WNDCLASSA *c);
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS);
@ -40,4 +47,20 @@ HRESULT WINAPI InterceptDirectDrawCreate(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUn
HRESULT WINAPI InterceptSurfaceGetDesc(LPDIRECTDRAWSURFACE lpDDSurface, LPDDSURFACEDESC lpDDSurfaceDesc);
VOID WINAPI InterceptSleep(DWORD dwMilliseconds);
typedef HRESULT (WINAPI *d3drmCreateFunction)(LPDIRECT3DRM FAR *lplpDirect3DRM);
extern d3drmCreateFunction d3drmCreateOriginal;
HRESULT WINAPI InterceptDirect3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM);
typedef HRESULT (WINAPI *dsCreateFunction)(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
extern dsCreateFunction dsCreateOriginal;
HRESULT WINAPI InterceptDirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
SHORT WINAPI InterceptGetAsyncKeyState(int vKey);
typedef HRESULT (WINAPI *dinputCreateFunction)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
extern dinputCreateFunction dinputCreateOriginal;
HRESULT WINAPI InterceptDirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter);
#endif // HOOKS_H

View file

@ -95,8 +95,9 @@ LPVOID OverwriteImport(LPVOID imageBase, LPCSTR overrideFunction, LPVOID overrid
PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((UINT_PTR)imageBase + (UINT_PTR)originalFirstThunk->u1.AddressOfData);
if (!strcmp((const char*)functionName->Name, overrideFunction)) {
LPVOID originalFunction = (LPVOID)firstThunk->u1.Function;
firstThunk->u1.Function = (PDWORD)override;
// Write to memory
LPVOID originalFunction;
WriteMemory(&firstThunk->u1.Function, &override, sizeof(LPVOID), &originalFunction);
// Return original function and end loop here
printf("Hooked %s\n", overrideFunction);
@ -117,12 +118,9 @@ LPVOID OverwriteVirtualTable(LPVOID object, SIZE_T methodIndex, LPVOID overrideF
{
LPVOID *vtable = ((LPVOID**)(object))[0];
LPVOID &functionAddress = vtable[methodIndex];
LPVOID originalFunction = functionAddress;
LPVOID originalFunction = NULL;
if (overrideFunction) {
functionAddress = overrideFunction;
printf("Hooked vtable %p+%lu\n", vtable, methodIndex);
}
WriteMemory(&functionAddress, overrideFunction ? &overrideFunction : NULL, sizeof(LPVOID), &originalFunction);
return originalFunction;
}

View file

@ -22,22 +22,23 @@ DWORD WINAPI Patch()
OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA);
OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA);
OverwriteImport(exeBase, "RegQueryValueExA", (LPVOID)InterceptRegQueryValueExA);
OverwriteImport(exeBase, "RegisterClassA", (LPVOID)InterceptRegisterClassA);
OverwriteImport(dllBase, "Sleep", (LPVOID)InterceptSleep);
OverwriteImport(exeBase, "Sleep", (LPVOID)InterceptSleep);
OverwriteImport(dllBase, "GetAsyncKeyState", (LPVOID)InterceptGetAsyncKeyState);
ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate);
d3drmCreateOriginal = (d3drmCreateFunction)OverwriteImport(dllBase, "Direct3DRMCreate", (LPVOID)InterceptDirect3DRMCreate);
dsCreateOriginal = (dsCreateFunction)OverwriteImport(dllBase, "DirectSoundCreate", (LPVOID)InterceptDirectSoundCreate);
dinputCreateOriginal = (dinputCreateFunction)OverwriteImport(dllBase, "DirectInputCreateA", (LPVOID)InterceptDirectInputCreateA);
// Stay active when defocused
if (config.GetInt(_T("StayActiveWhenDefocused"))) {
// Patch jump if window isn't active
// Patch jump if window isn't active (TODO: Replace with C++ patch)
SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3);
// Patch DirectSound flags so that sound doesn't mute when inactive
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xE0\x00\x00\x00", "\xC7\x44\x24\x24\xE0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xB0\x00\x00\x00", "\xC7\x44\x24\x24\xB0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\x11\x00\x00\x00", "\xC7\x45\xCC\x11\x80\x00\x00", 7);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\xE0\x00\x00\x00", "\xC7\x45\xCC\xE0\x80\x00\x00", 7);
}
// Allow multiple instances
if (config.GetInt(_T("AllowMultipleInstances"))) {
if (config.GetInt(_T("MultipleInstances"))) {
// Patch FindWindowA import to always tell ISLE that no other ISLE window exists
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
}
@ -50,12 +51,87 @@ DWORD WINAPI Patch()
SearchReplacePattern(dllBase, "OGEL", "\x0GEL", 4, TRUE);
}
// Disable auto-finish in build sections
if (config.GetInt(_T("DisableAutoFinishBuilding"))) {
// Pattern used in August build (jump is much shorter so it uses a different opcode)
const char *autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x75";
const char *autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xEB";
if (SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 8) == 0) {
// Pattern used in September build (jump is much longer)
autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x0F\x85\x86\x00\x00\x00";
autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xE9\x87\x00\x00\x00\x90";
SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 13);
}
}
// Patch navigation
{
const int nav_block_sz = 0x30;
const char *nav_block_src = "\x28\x00\x00\x00\x6F\x12\x83\x3A\x00\x00\x20\x42\x00\x00\xA0\x41\x00\x00\x70\x41\x00\x00\xF0\x41\x00\x00\x80\x40\x00\x00\x70\x41\x00\x00\x48\x42\x00\x00\x48\x42\xCD\xCC\xCC\x3E\x00\x00\x00\x00";
char nav_block_dst[nav_block_sz];
memcpy(nav_block_dst, nav_block_src, nav_block_sz);
UINT32 mouse_deadzone = config.GetInt(_T("MouseDeadzone"), 40);
memcpy(nav_block_dst+0x0, &mouse_deadzone, sizeof(mouse_deadzone));
// DDRAW GetSurfaceDesc Override
OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc);
float movement_max_spd = config.GetFloat(_T("MovementMaxSpeed"), 40.0f);
memcpy(nav_block_dst+0x8, &movement_max_spd, sizeof(movement_max_spd));
float turn_max_spd = config.GetFloat(_T("TurnMaxSpeed"), 20.0f);
memcpy(nav_block_dst+0xC, &turn_max_spd, sizeof(turn_max_spd));
float movement_max_accel = config.GetFloat(_T("MovementMaxAcceleration"), 15.0f);
memcpy(nav_block_dst+0x10, &movement_max_accel, sizeof(movement_max_accel));
float turn_max_accel = config.GetFloat(_T("TurnMaxAcceleration"), 30.0f);
memcpy(nav_block_dst+0x14, &turn_max_accel, sizeof(turn_max_accel));
float movement_min_accel = config.GetFloat(_T("MovementMinAcceleration"), 4.0f);
memcpy(nav_block_dst+0x18, &movement_min_accel, sizeof(movement_min_accel));
float turn_min_accel = config.GetFloat(_T("TurnMinAcceleration"), 15.0f);
memcpy(nav_block_dst+0x1C, &turn_min_accel, sizeof(turn_min_accel));
float movement_decel = config.GetFloat(_T("MovementDeceleration"), 50.0f);
memcpy(nav_block_dst+0x20, &movement_decel, sizeof(movement_decel));
float turn_decel = config.GetFloat(_T("TurnDeceleration"), 50.0f);
memcpy(nav_block_dst+0x24, &turn_decel, sizeof(turn_decel));
UINT32 turn_use_velocity = config.GetInt(_T("TurnUseVelocity"), FALSE);
memcpy(nav_block_dst+0x2C, &turn_use_velocity, sizeof(turn_use_velocity));
SearchReplacePattern(dllBase, nav_block_src, nav_block_dst, nav_block_sz);
}
// Model Quality
std::string model_quality = config.GetString("ModelQuality");
float mq_val = 3.6f;
if (model_quality == "Infinite") {
mq_val = 999999.0f;
} else if (model_quality == "High") {
mq_val = 5.0f;
} else if (model_quality == "Medium") {
mq_val = 3.6f;
} else if (model_quality == "Low") {
mq_val = 0.0f;
}
const char *mq_pattern = "\x00\x00\x80\x40\x66\x66\x66\x40";
char mq_replace[8];
memcpy(mq_replace, mq_pattern, 8);
memcpy(mq_replace+4, &mq_val, sizeof(mq_val));
SearchReplacePattern(dllBase, mq_pattern, mq_replace, 8);
// Field of view
const char *fov_pattern = "\x00\x00\x00\x3F\x17\x6C\xC1\x16\x6C\xC1\x76\x3F";
char fov_replace[12];
float fov;
memcpy(fov_replace, fov_pattern, 12); // Make editable copy of pattern
memcpy(&fov, fov_replace, sizeof(fov)); // Get float from bytes
fov *= 1.0f/config.GetFloat(_T("FOVMultiplier")); // Multiply FOV
memcpy(fov_replace, &fov, sizeof(fov)); // Store back into bytes
SearchReplacePattern(dllBase, fov_pattern, fov_replace, 12);
// Window size hack
/*SearchReplacePattern(exeBase,

View file

@ -1,5 +1,6 @@
#include "patchgrid.h"
#include <SHLWAPI.H>
#include <SSTREAM>
#include "../cmn/path.h"
@ -123,8 +124,8 @@ PatchGrid::PatchGrid()
AddPatch("FOVMultiplier",
_T("Globally adjusts the field of view by a multiplier\n\n"
"0.1 = Default (smaller than 0.1 is more zoomed in, larger than 0.1 is more zoomed out"),
AddDoubleItem(sectionGraphics, _T("Field of View Adjustment"), 0.1));
"1.0 = Default (greater than 1.0 is zoomed in, less than 1.0 is zoomed out)"),
AddDoubleItem(sectionGraphics, _T("Field of View Adjustment"), 1.0));
// Audio section
HSECTION sectionMusic = AddSection(_T("Audio"));
@ -142,6 +143,61 @@ std::string toString(const T &value)
return oss.str();
}
void PatchGrid::LoadConfiguration(LPCTSTR filename)
{
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) {
CItem *item = FindItem(it->second);
std::string value;
value.resize(1024);
char buf[1024];
DWORD sz = GetPrivateProfileString(appName, it->first.c_str(), NULL, &value[0], value.size(), filename);
// If this entry wasn't in the profile, skip it
if (!sz) {
continue;
}
value.resize(sz);
// Convert value to string
switch (item->m_type) {
case IT_STRING:
case IT_TEXT:
case IT_FILE:
case IT_FOLDER:
case IT_COMBO:
SetItemValue(it->second, value);
break;
case IT_BOOLEAN:
SetItemValue(it->second, (bool)StrToIntA(value.c_str()));
break;
case IT_INTEGER:
SetItemValue(it->second, StrToIntA(value.c_str()));
break;
case IT_DOUBLE:
SetItemValue(it->second, atof(value.c_str()));
break;
case IT_COLOR:
SetItemValue(it->second, (COLORREF) StrToIntA(value.c_str()));
break;
case IT_CUSTOM:
case IT_DATE:
case IT_DATETIME:
case IT_FONT:
{
// Report inability to serialize
TCHAR buf[200];
sprintf(buf, "Failed to serialize %s from string.", it->first.c_str());
MessageBox(buf);
break;
}
}
}
}
BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
{
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) {
@ -155,20 +211,30 @@ BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
case IT_TEXT:
case IT_FILE:
case IT_FOLDER:
value = item->m_strValue;
case IT_COMBO:
GetItemValue(it->second, value);
break;
case IT_BOOLEAN:
value = toString(item->m_bValue);
{
bool b;
GetItemValue(it->second, b);
value = toString(b);
break;
case IT_COMBO:
}
case IT_INTEGER:
value = toString(item->m_nValue);
int i;
GetItemValue(it->second, i);
value = toString(i);
break;
case IT_DOUBLE:
value = toString(item->m_dValue);
double d;
GetItemValue(it->second, d);
value = toString(d);
break;
case IT_COLOR:
value = toString(item->m_clrValue);
COLORREF c;
GetItemValue(it->second, c);
value = toString(c);
break;
case IT_CUSTOM:
case IT_DATE:
@ -183,7 +249,6 @@ BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
}
}
this->GetItemValue(it->second, value);
if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) {
return FALSE;
}

View file

@ -9,6 +9,7 @@ class PatchGrid : public CPropertyGrid
public:
PatchGrid();
void LoadConfiguration(LPCTSTR filename);
BOOL SaveConfiguration(LPCTSTR filename);
private:

View file

@ -78,6 +78,16 @@ CRebuilderWindow::CRebuilderWindow()
RECT patchGridClientRect;
m_cPatchGrid.GetClientRect(&patchGridClientRect);
m_cPatchGrid.SetGutterWidth((patchGridClientRect.right - patchGridClientRect.left) / 2);
TCHAR configPath[MAX_PATH];
if (GetConfigFilename(configPath)) {
m_cPatchGrid.LoadConfiguration(configPath);
}
}
CRebuilderWindow::~CRebuilderWindow()
{
TrySaving();
}
DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
@ -88,26 +98,35 @@ DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
return 0;
}
void CRebuilderWindow::OnRunClick()
BOOL CRebuilderWindow::TrySaving()
{
TCHAR configPath[MAX_PATH];
if (GetConfigFilename(configPath)) {
if (m_cPatchGrid.SaveConfiguration(configPath)) {
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
m_lProcesses.push_back(proc);
SwitchButtonMode(TRUE);
// Register callback when process exits
DWORD threadId; // We don't use this, but Windows 95 will fail without it
CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForProcessToClose, proc, 0, &threadId));
}
return TRUE;
} else {
MessageBox(_T("Failed to save configuration file."));
}
} else {
MessageBox(_T("Failed to determine configuration path."));
}
return FALSE;
}
void CRebuilderWindow::OnRunClick()
{
if (TrySaving()) {
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
m_lProcesses.push_back(proc);
SwitchButtonMode(TRUE);
// Register callback when process exits
DWORD threadId; // We don't use this, but Windows 95 will fail without it
CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForProcessToClose, proc, 0, &threadId));
}
}
}
void CRebuilderWindow::OnKillClick()

View file

@ -13,6 +13,8 @@ class CRebuilderWindow : public CFrameWnd
public:
CRebuilderWindow();
~CRebuilderWindow();
afx_msg void OnRunClick();
afx_msg void OnKillClick();
@ -34,6 +36,8 @@ private:
void SwitchButtonMode(BOOL running);
BOOL TrySaving();
enum {
ID_RUN = 1000,
ID_KILL,