ported some patches

This commit is contained in:
itsmattkc 2021-09-22 12:16:20 -07:00
parent f5dae0804a
commit f0904e54b9
12 changed files with 346 additions and 100 deletions

View file

@ -11,6 +11,10 @@ option(BUILD_UNICODE "Build with Unicode support" ON)
# Build our code injected DLL # Build our code injected DLL
# #
add_library(Rebld SHARED add_library(Rebld SHARED
cmn/path.cpp
cmn/path.h
lib/config.cpp
lib/config.h
lib/dllmain.cpp lib/dllmain.cpp
lib/hooks.cpp lib/hooks.cpp
lib/hooks.h lib/hooks.h
@ -21,7 +25,7 @@ add_library(Rebld SHARED
lib/worker.h lib/worker.h
) )
target_compile_options(Rebld PRIVATE /MT) target_compile_options(Rebld PRIVATE /MT)
target_link_libraries(Rebld PRIVATE winmm.lib) target_link_libraries(Rebld PRIVATE winmm.lib shlwapi.lib)
# Add property grid # Add property grid
set(PROPERTYGRID_BUILD_APP OFF CACHE BOOL "") set(PROPERTYGRID_BUILD_APP OFF CACHE BOOL "")
@ -31,6 +35,8 @@ add_subdirectory(ext/PropertyGrid)
# Build launcher/configuration executable # Build launcher/configuration executable
# #
add_executable(Rebuilder WIN32 add_executable(Rebuilder WIN32
cmn/path.cpp
cmn/path.h
res/res.rc res/res.rc
res/resource.h res/resource.h
src/app.cpp src/app.cpp

11
cmn/combo.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COMBO_H
#define COMBO_H
enum ModelQuality {
kModelQualityInfinite,
kModelQualityHigh,
kModelQualityMedium,
kModelQualityLow
};
#endif // COMBO_H

94
cmn/path.cpp Normal file
View file

@ -0,0 +1,94 @@
#include "path.h"
#include <SHLOBJ.H>
#include <SHLWAPI.H>
#include <STRING>
#include <TCHAR.H>
LPCTSTR appName = TEXT("Rebuilder");
BOOL DirectoryExists(LPCTSTR szPath)
{
return PathFileExists(szPath) && PathIsDirectory(szPath);
}
BOOL RecursivelyCreateDirectory(LPCTSTR directory)
{
if (DirectoryExists(directory)) {
// Directory already exists, do nothing
return TRUE;
} else {
// Determine directory of this directory
std::basic_string<TCHAR> copy = directory;
PathRemoveFileSpec(&copy[0]);
// Create if necessary
if (RecursivelyCreateDirectory(copy.c_str())) {
return CreateDirectory(directory, NULL);
} else {
return FALSE;
}
}
}
#ifdef UNICODE
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
#else
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
#endif
BOOL GetAppDataPath(LPTSTR s)
{
OSVERSIONINFO info;
ZeroMemory(&info, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
// Dynamically link to SHGetSpecialFolderPath because not all versions of Windows have it
#ifdef UNICODE
LPCSTR functionName = "SHGetSpecialFolderPathW";
#else
LPCSTR functionName = "SHGetSpecialFolderPathA";
#endif
SHGetSpecialFolderPathSignature GetSpecialFolderPath = (SHGetSpecialFolderPathSignature)GetProcAddress(GetModuleHandle(_T("SHELL32.DLL")), functionName);
BOOL haveDir = FALSE;
BOOL usedShell = FALSE;
if (GetSpecialFolderPath) {
haveDir = GetSpecialFolderPath(NULL, s, CSIDL_APPDATA, TRUE);
usedShell = TRUE;
} else {
// Assume we're on Windows 95 which has no application data folder, we bodge it to write to
// "C:\Windows\Application Data" which is roughly where 98/Me would do it
GetWindowsDirectory(s, MAX_PATH);
_tcscat(s, _T("\\Application Data"));
haveDir = TRUE;
}
//MessageBox(0, s, usedShell ? _T("Using API") : _T("Is this Windows 95?"), 0);
return haveDir;
}
BOOL GetConfigFilename(LPTSTR s)
{
if (GetAppDataPath(s)) {
_tcscat(s, _T("\\LEGOIslandRebuilder"));
if (RecursivelyCreateDirectory(s)) {
_tcscat(s, _T("\\settings.ini"));
return TRUE;
}
}
return FALSE;
}
BOOL GetSafeLEGOIslandSavePath(LPTSTR s)
{
if (GetAppDataPath(s)) {
_tcscat(s, _T("\\LEGO Island"));
if (RecursivelyCreateDirectory(s)) {
return TRUE;
}
}
return FALSE;
}

12
cmn/path.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PATH_H
#define PATH_H
#include <WINDOWS.H>
BOOL GetSafeLEGOIslandSavePath(LPTSTR s);
BOOL GetConfigFilename(LPTSTR s);
extern LPCTSTR appName;
#endif // PATH_H

24
lib/config.cpp Normal file
View file

@ -0,0 +1,24 @@
#include "config.h"
#include <SHLWAPI.H>
#include "../cmn/path.h"
Config config;
Config::Config()
{
}
BOOL Config::Load()
{
// Get config file
m_configFile.resize(MAX_PATH);
return GetConfigFilename(&m_configFile[0]) && PathFileExists(m_configFile.c_str());
}
UINT Config::GetInt(LPCTSTR name, UINT defaultValue)
{
return GetPrivateProfileInt(appName, name, defaultValue, m_configFile.c_str());
}

24
lib/config.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <STRING>
#include <TCHAR.H>
#include <WINDOWS.H>
class Config
{
public:
Config();
BOOL Load();
UINT GetInt(LPCTSTR name, UINT defaultValue = 0);
private:
std::basic_string<TCHAR> m_configFile;
};
extern Config config;
#endif // CONFIG_H

View file

@ -2,19 +2,23 @@
#include <STDIO.H> #include <STDIO.H>
#include "../cmn/path.h"
#include "config.h"
#include "util.h" #include "util.h"
HWND isleWindow = NULL;
void InterceptOutputDebugStringA(LPCSTR s) void InterceptOutputDebugStringA(LPCSTR s)
{ {
printf("%s\n", s); printf("%s\n", s);
MessageBoxA(0,s,"LEGO Island sez",0); MessageBoxA(isleWindow, s, "LEGO Island sez", 0);
} }
HWND WINAPI InterceptCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) HWND WINAPI InterceptCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
{ {
HWND window = CreateWindowExA(dwExStyle, lpClassName, "LEGO Island: Rebuilt", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); // Grab a copy of the ISLE window so we can do stuff with it
isleWindow = CreateWindowExA(dwExStyle, lpClassName, "LEGO Island: Rebuilt", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
return window; return isleWindow;
} }
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName) HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
@ -106,10 +110,71 @@ HRESULT WINAPI InterceptDirectDrawCreate(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUn
{ {
HRESULT res = ddCreateOriginal(lpGUID, lplpDD, pUnkOuter); HRESULT res = ddCreateOriginal(lpGUID, lplpDD, pUnkOuter);
if (res == DD_OK && !originalGetDisplayMode) { if (res == DD_OK) {
originalGetDisplayMode = (ddGetDisplayModeFunction)OverwriteVirtualTable(*lplpDD, 0xC, (LPVOID)InterceptGetDisplayMode); if (!originalGetDisplayMode) {
originalCreateSurfaceFunction = (ddCreateSurfaceFunction)OverwriteVirtualTable(*lplpDD, 0x6, (LPVOID)InterceptCreateSurface); originalGetDisplayMode = (ddGetDisplayModeFunction)OverwriteVirtualTable(*lplpDD, 0xC, (LPVOID)InterceptGetDisplayMode);
}
ddCreateSurfaceFunction f = (ddCreateSurfaceFunction)OverwriteVirtualTable(*lplpDD, 0x6, (LPVOID)InterceptCreateSurface);
if (f != InterceptCreateSurface) {
originalCreateSurfaceFunction = f;
}
} }
return res; return res;
} }
void ReturnRegistryYESNOFromBool(LPBYTE lpData, BOOL value)
{
strcpy((char*)lpData, value ? "YES" : "NO");
}
LONG WINAPI InterceptRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
if (!strcmp(lpValueName, "Music")) {
// Music option
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("MusicToggle"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "UseJoystick")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("UseJoystick"), 0));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "Full Screen")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("FullScreen"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "Draw Cursor")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("DrawCursor"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "savepath")) {
// If enabled, return a safe %APPDATA% based save location rather than its default
// "C:\Program Files" location
if (config.GetInt(_T("RedirectSaveData"))) {
// Generate directory
TCHAR save_path[MAX_PATH];
if (GetSafeLEGOIslandSavePath(save_path)) {
strcpy((char*)lpData, save_path);
return ERROR_SUCCESS;
} else {
MessageBoxA(isleWindow, "Failed to redirect save path. Default will be used instead.", 0, 0);
}
}
} else if (!strcmp(lpValueName, "diskpath") || !strcmp(lpValueName, "cdpath")) {
// Pass through
} else {
MessageBoxA(isleWindow, lpValueName, "ISLE asked for...", 0);
}
// Pass these through
return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
}

View file

@ -21,6 +21,17 @@ HWND WINAPI InterceptCreateWindowExA(
LPVOID lpParam LPVOID lpParam
); );
LONG
APIENTRY
InterceptRegQueryValueExA (
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName); HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS); typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS);

View file

@ -1,13 +1,18 @@
#include "worker.h" #include "worker.h"
#include <TCHAR.H>
#include <VECTOR> #include <VECTOR>
#include "config.h"
#include "hooks.h" #include "hooks.h"
#include "util.h" #include "util.h"
DWORD WINAPI Patch() DWORD WINAPI Patch()
{ {
MessageBoxA(0,"Connect debugger now",0,0); if (!config.Load()) {
MessageBoxA(0, "Failed to find Rebuilder configuration. No patches will be active.", 0, 0);
return 1;
}
// Hook import address table // Hook import address table
LPVOID exeBase = GetModuleHandle(TEXT("ISLE.EXE")); LPVOID exeBase = GetModuleHandle(TEXT("ISLE.EXE"));
@ -15,31 +20,47 @@ DWORD WINAPI Patch()
// Redirect various imports // Redirect various imports
OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA); OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA);
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA); OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA);
OverwriteImport(exeBase, "RegQueryValueExA", (LPVOID)InterceptRegQueryValueExA);
ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate); ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate);
// Stay active when defocused // Stay active when defocused
SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3); if (config.GetInt(_T("StayActiveWhenDefocused"))) {
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xE0\x00\x00\x00", "\xC7\x44\x24\x24\xE0\x80\x00\x00", 8); // Patch jump if window isn't active
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xB0\x00\x00\x00", "\xC7\x44\x24\x24\xB0\x80\x00\x00", 8); SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3);
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); // 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"))) {
// Patch FindWindowA import to always tell ISLE that no other ISLE window exists
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
}
// Debug mode
if (config.GetInt(_T("DebugToggle"))) {
// LEGO1 uses a string pointer to know if OGEL has been typed, if the string pointer sees 0x0
// (null-terminator/end of string), then debug mode is enabled. So we just replace the first
// character with 0x0 and it's permanently on.
SearchReplacePattern(dllBase, "OGEL", "\x0GEL", 4, TRUE);
}
// DDRAW GetSurfaceDesc Override // DDRAW GetSurfaceDesc Override
//OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc); OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc);
// Window size hack // Window size hack
/*SearchReplacePattern(exeBase, /*SearchReplacePattern(exeBase,
"\x80\x02\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", "\x80\x02\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00",
"\x40\x01\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", 24);*/ "\x40\x01\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", 24);*/
/*char debug[5];
debug[0] = 0xE8;
*(UINT_PTR*)(&debug[1]) = (UINT_PTR)InterceptOutputDebugStringA;
if (SIZE_T replacements = SearchReplacePattern(legoBase, "\xE8\x34\x08\x00\x00", debug, 5)) {
printf("Hooked some other debug function %lu times", replacements);
}*/
return 0; return 0;
} }

View file

@ -1,5 +1,9 @@
#include "patchgrid.h" #include "patchgrid.h"
#include <SSTREAM>
#include "../cmn/path.h"
PatchGrid::PatchGrid() PatchGrid::PatchGrid()
{ {
SetBoldModified(true); SetBoldModified(true);
@ -39,13 +43,14 @@ PatchGrid::PatchGrid()
HSECTION sectionControls = AddSection(_T("Controls")); HSECTION sectionControls = AddSection(_T("Controls"));
AddPatch("UseWASD", AddPatch("UseWASD",
_T(""), _T("Enables the use of WASD keys for movement rather than the arrow keys. "
"NOTE: When using Debug Mode, this patch will re-map the conflicting debug keys to the arrow keys."),
AddBoolItem(sectionControls, _T("Use WASD"), false)); AddBoolItem(sectionControls, _T("Use WASD"), false));
AddPatch("UseJoystick", AddPatch("UseJoystick",
_T(""), _T("Enables Joystick functionality."),
AddBoolItem(sectionControls, _T("Use Joystick"), false)); AddBoolItem(sectionControls, _T("Use Joystick"), false));
AddPatch("MouseDeadzone", AddPatch("MouseDeadzone",
_T(""), _T("Sets the radius from the center of the screen where the mouse will do nothing (40 = default)."),
AddIntegerItem(sectionControls, _T("Mouse Deadzone"), 40)); AddIntegerItem(sectionControls, _T("Mouse Deadzone"), 40));
AddPatch("UnhookTurnSpeed", AddPatch("UnhookTurnSpeed",
_T("LEGO Island contains a bug where the turning speed is influenced by the frame rate. Enable this to make the turn speed independent of the frame rate."), _T("LEGO Island contains a bug where the turning speed is influenced by the frame rate. Enable this to make the turn speed independent of the frame rate."),
@ -129,12 +134,55 @@ PatchGrid::PatchGrid()
AddBoolItem(sectionMusic, _T("Play Music"), true)); AddBoolItem(sectionMusic, _T("Play Music"), true));
} }
template<typename T>
std::string toString(const T &value)
{
std::ostringstream oss;
oss << value;
return oss.str();
}
BOOL PatchGrid::SaveConfiguration(LPCTSTR filename) BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
{ {
LPCTSTR appName = TEXT("Rebuilder");
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) { 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; std::string value;
// Convert value to string
switch (item->m_type) {
case IT_STRING:
case IT_TEXT:
case IT_FILE:
case IT_FOLDER:
value = item->m_strValue;
break;
case IT_BOOLEAN:
value = toString(item->m_bValue);
break;
case IT_COMBO:
case IT_INTEGER:
value = toString(item->m_nValue);
break;
case IT_DOUBLE:
value = toString(item->m_dValue);
break;
case IT_COLOR:
value = toString(item->m_clrValue);
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 to string.", it->first.c_str());
MessageBox(buf);
break;
}
}
this->GetItemValue(it->second, value); this->GetItemValue(it->second, value);
if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) { if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) {
return FALSE; return FALSE;

View file

@ -1,8 +1,8 @@
#include "window.h" #include "window.h"
#include <SHLWAPI.H>
#include <WINDOWS.H> #include <WINDOWS.H>
#include "../cmn/path.h"
#include "launcher.h" #include "launcher.h"
#include "../res/resource.h" #include "../res/resource.h"
@ -91,10 +91,8 @@ DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
void CRebuilderWindow::OnRunClick() void CRebuilderWindow::OnRunClick()
{ {
TCHAR configPath[MAX_PATH]; TCHAR configPath[MAX_PATH];
if (GetConfigPath(configPath)) {
// Append path and save configuration
_tcscat(configPath, _T("\\settings.ini"));
if (GetConfigFilename(configPath)) {
if (m_cPatchGrid.SaveConfiguration(configPath)) { if (m_cPatchGrid.SaveConfiguration(configPath)) {
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) { if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
m_lProcesses.push_back(proc); m_lProcesses.push_back(proc);
@ -252,72 +250,6 @@ void CRebuilderWindow::SwitchButtonMode(BOOL running)
} }
} }
BOOL DirectoryExists(LPCTSTR szPath)
{
return PathFileExists(szPath) && PathIsDirectory(szPath);
}
BOOL RecursivelyCreateDirectory(LPCTSTR directory)
{
if (DirectoryExists(directory)) {
// Directory already exists, do nothing
return TRUE;
} else {
// Determine directory of this directory
std::basic_string<TCHAR> copy = directory;
PathRemoveFileSpec(&copy[0]);
// Create if necessary
if (RecursivelyCreateDirectory(copy.c_str())) {
return CreateDirectory(directory, NULL);
} else {
return FALSE;
}
}
}
#ifdef UNICODE
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
#else
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
#endif
BOOL CRebuilderWindow::GetConfigPath(LPTSTR s)
{
OSVERSIONINFO info;
ZeroMemory(&info, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
// Dynamically link to SHGetSpecialFolderPath because not all versions of Windows have it
#ifdef UNICODE
LPCSTR functionName = "SHGetSpecialFolderPathW";
#else
LPCSTR functionName = "SHGetSpecialFolderPathA";
#endif
SHGetSpecialFolderPathSignature GetSpecialFolderPath = (SHGetSpecialFolderPathSignature)GetProcAddress(GetModuleHandle(_T("SHELL32.DLL")), functionName);
BOOL haveDir = FALSE;
BOOL usedShell = FALSE;
if (GetSpecialFolderPath) {
haveDir = GetSpecialFolderPath(NULL, s, CSIDL_APPDATA, TRUE);
usedShell = TRUE;
} else {
// Assume we're on Windows 95 which has no application data folder, we bodge it to write to
// "C:\Windows\Application Data" which is roughly where 98/Me would do it
GetWindowsDirectory(s, MAX_PATH);
_tcscat(s, _T("\\Application Data"));
haveDir = TRUE;
}
if (haveDir) {
_tcscat(s, _T("\\LEGOIslandRebuilder"));
MessageBox(s, usedShell ? _T("Using API") : _T("Is this Windows 95?"));
return RecursivelyCreateDirectory(s);
} else {
return FALSE;
}
}
BEGIN_MESSAGE_MAP(CRebuilderWindow, super) BEGIN_MESSAGE_MAP(CRebuilderWindow, super)
ON_WM_SIZE() ON_WM_SIZE()
ON_WM_GETMINMAXINFO() ON_WM_GETMINMAXINFO()

View file

@ -34,8 +34,6 @@ private:
void SwitchButtonMode(BOOL running); void SwitchButtonMode(BOOL running);
BOOL GetConfigPath(LPTSTR s);
enum { enum {
ID_RUN = 1000, ID_RUN = 1000,
ID_KILL, ID_KILL,