mirror of
https://github.com/AppleWin/AppleWin.git
synced 2026-10-25 14:03:18 +00:00
1. Registry functions The set of functions are changed to consistently use bool arguments. The macros are changed to inline functions to improve type checking. RegSaveValue() are overloaded with help of templates to reduce typecasting at call sites. For instance, bool value would be converted consistently instead of relying on call sites to convert bool to int values. 2. Memory functions BOOL usages were unnecessary. Mostly internal usages which can simply be bool. 3. FrameBase Some member variables are changed to bool. BOOL was used because of those Registry functions. Additional changes: - Some expressions are forced to be bool when assigning to bool variables.
1049 lines
32 KiB
C++
1049 lines
32 KiB
C++
/*
|
|
AppleWin : An Apple //e emulator for Windows
|
|
|
|
Copyright (C) 1994-1996, Michael O'Brien
|
|
Copyright (C) 1999-2001, Oliver Schmidt
|
|
Copyright (C) 2002-2005, Tom Charlesworth
|
|
Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski
|
|
|
|
AppleWin is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
AppleWin is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with AppleWin; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/* Description: main
|
|
*
|
|
* Author: Various
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "Windows/AppleWin.h"
|
|
#include "Windows/HookFilter.h"
|
|
#include "Interface.h"
|
|
#include "Utilities.h"
|
|
#include "CmdLine.h"
|
|
#include "Debug.h"
|
|
#include "Keyboard.h"
|
|
#include "Log.h"
|
|
#include "Memory.h"
|
|
#include "Mockingboard.h"
|
|
#include "MouseInterface.h"
|
|
#include "ParallelPrinter.h"
|
|
#include "Registry.h"
|
|
#include "Riff.h"
|
|
#include "SaveState.h"
|
|
#include "SerialComms.h"
|
|
#include "Speaker.h"
|
|
#include "LanguageCard.h"
|
|
#include "CardManager.h"
|
|
#ifdef USE_SPEECH_API
|
|
#include "Speech.h"
|
|
#endif
|
|
#include "Windows/Win32Frame.h"
|
|
#include "Windows/DXSoundBuffer.h"
|
|
#include "RGBMonitor.h"
|
|
#include "NTSC.h"
|
|
|
|
#include "Configuration/About.h"
|
|
#include "Configuration/PropertySheet.h"
|
|
|
|
//=================================================
|
|
|
|
static bool g_bLoadedSaveState = false;
|
|
static bool g_bSysClkOK = false;
|
|
|
|
bool g_bRestartFullScreen = false;
|
|
|
|
static bool g_fullScreenResolutionChangedByUser = false;
|
|
|
|
//===========================================================================
|
|
|
|
bool GetLoadedSaveStateFlag(void)
|
|
{
|
|
return g_bLoadedSaveState;
|
|
}
|
|
|
|
void Win32Frame::SetLoadedSaveStateFlag(const bool bFlag)
|
|
{
|
|
g_bLoadedSaveState = bFlag;
|
|
}
|
|
|
|
bool GetHookAltTab(void)
|
|
{
|
|
return g_bHookAltTab;
|
|
}
|
|
|
|
bool GetHookAltGrControl(void)
|
|
{
|
|
return g_bHookAltGrControl;
|
|
}
|
|
|
|
bool GetFullScreenResolutionChangedByUser(void)
|
|
{
|
|
return g_fullScreenResolutionChangedByUser;
|
|
}
|
|
|
|
static void ResetToLogoMode(void)
|
|
{
|
|
g_nAppMode = MODE_LOGO;
|
|
GetFrame().SetLoadedSaveStateFlag(false);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static bool g_bPriorityNormal = true;
|
|
|
|
// Make APPLEWIN process higher priority
|
|
void SetPriorityAboveNormal(void)
|
|
{
|
|
if (!g_bPriorityNormal)
|
|
return;
|
|
|
|
if ( SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) )
|
|
{
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
g_bPriorityNormal = false;
|
|
}
|
|
}
|
|
|
|
// Make APPLEWIN process normal priority
|
|
void SetPriorityNormal(void)
|
|
{
|
|
if (g_bPriorityNormal)
|
|
return;
|
|
|
|
if ( SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS) )
|
|
{
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
|
|
g_bPriorityNormal = true;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static UINT g_uModeStepping_Cycles = 0;
|
|
static bool g_uModeStepping_LastGetKey_ScrollLock = false;
|
|
|
|
static void ContinueExecution(void)
|
|
{
|
|
#ifdef LOG_PERF_TIMINGS
|
|
PerfMarker* pPerfMarkerTotal = new PerfMarker(g_timeTotal);
|
|
#endif
|
|
|
|
_ASSERT(g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING);
|
|
|
|
const double fUsecPerSec = 1.e6;
|
|
#if 1
|
|
const UINT nExecutionPeriodUsec = 1000; // 1.0ms
|
|
// const UINT nExecutionPeriodUsec = 100; // 0.1ms
|
|
const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec);
|
|
#else
|
|
const double fExecutionPeriodClks = 1800.0;
|
|
const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502));
|
|
#endif
|
|
|
|
//
|
|
|
|
bool bScrollLock_FullSpeed = false;
|
|
if (GetPropertySheet().GetScrollLockToggle())
|
|
{
|
|
bScrollLock_FullSpeed = Win32Frame::GetWin32Frame().g_bScrollLock_FullSpeed;
|
|
}
|
|
else
|
|
{
|
|
if (g_nAppMode == MODE_RUNNING)
|
|
{
|
|
bScrollLock_FullSpeed = GetKeyState(VK_SCROLL) < 0;
|
|
}
|
|
else if (!IsDebugSteppingAtFullSpeed()) // Implicitly: MODE_STEPPING
|
|
{
|
|
// NB. For MODE_STEPPING: GetKeyState() is slow, so only call periodically
|
|
// . 0x3FFF is roughly the number of cycles in a video frame, which seems a reasonable rate to call GetKeyState()
|
|
if ((g_uModeStepping_Cycles & 0x3FFF) == 0)
|
|
g_uModeStepping_LastGetKey_ScrollLock = GetKeyState(VK_SCROLL) < 0;
|
|
|
|
bScrollLock_FullSpeed = g_uModeStepping_LastGetKey_ScrollLock;
|
|
}
|
|
}
|
|
|
|
const bool bWasFullSpeed = g_bFullSpeed;
|
|
g_bFullSpeed = (g_dwSpeed == SPEED_MAX) ||
|
|
bScrollLock_FullSpeed ||
|
|
(GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !GetCardMgr().GetMockingboardCardMgr().IsActiveToPreventFullSpeed()) ||
|
|
IsDebugSteppingAtFullSpeed();
|
|
|
|
if (g_bFullSpeed)
|
|
{
|
|
if (!bWasFullSpeed)
|
|
GetFrame().VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode
|
|
|
|
// Don't call Spkr_Mute() - will get speaker clicks
|
|
GetCardMgr().GetMockingboardCardMgr().MuteControl(true);
|
|
SysClk_StopTimer();
|
|
#ifdef USE_SPEECH_API
|
|
g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out
|
|
#endif
|
|
|
|
g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number
|
|
|
|
// Switch to normal priority so that APPLEWIN process doesn't hog machine!
|
|
//. EG: No disk in Drive-1, and boot Apple: Windows will start to crawl!
|
|
SetPriorityNormal();
|
|
}
|
|
else
|
|
{
|
|
if (bWasFullSpeed)
|
|
GetFrame().VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame);
|
|
|
|
// Don't call Spkr_Unmute()
|
|
GetCardMgr().GetMockingboardCardMgr().MuteControl(false);
|
|
SysClk_StartTimerUsec(nExecutionPeriodUsec);
|
|
|
|
// Switch to higher priority, eg. for audio (BUG #015394)
|
|
SetPriorityAboveNormal();
|
|
}
|
|
|
|
//
|
|
|
|
int nCyclesWithFeedback = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback;
|
|
const UINT uCyclesToExecuteWithFeedback = (nCyclesWithFeedback >= 0) ? nCyclesWithFeedback
|
|
: 0;
|
|
|
|
const uint32_t uCyclesToExecute = (g_nAppMode == MODE_RUNNING) ? uCyclesToExecuteWithFeedback
|
|
/* MODE_STEPPING */ : 0;
|
|
|
|
const bool bVideoUpdate = !g_bFullSpeed;
|
|
const uint32_t uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate);
|
|
g_dwCyclesThisFrame += uActualCyclesExecuted;
|
|
|
|
GetCardMgr().Update(uActualCyclesExecuted);
|
|
|
|
//
|
|
|
|
uint32_t uSpkrActualCyclesExecuted = uActualCyclesExecuted;
|
|
|
|
bool bModeStepping_WaitTimer = false;
|
|
if (g_nAppMode == MODE_STEPPING && !IsDebugSteppingAtFullSpeed())
|
|
{
|
|
g_uModeStepping_Cycles += uActualCyclesExecuted;
|
|
if (g_uModeStepping_Cycles >= uCyclesToExecuteWithFeedback)
|
|
{
|
|
uSpkrActualCyclesExecuted = g_uModeStepping_Cycles;
|
|
|
|
g_uModeStepping_Cycles -= uCyclesToExecuteWithFeedback;
|
|
bModeStepping_WaitTimer = true;
|
|
}
|
|
}
|
|
|
|
// For MODE_STEPPING: do this speaker update periodically
|
|
// - Otherwise kills performance due to sound-buffer lock/unlock for every 6502 opcode!
|
|
if (g_nAppMode == MODE_RUNNING || bModeStepping_WaitTimer)
|
|
SpkrUpdate(uSpkrActualCyclesExecuted);
|
|
|
|
//
|
|
|
|
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
|
|
if (g_dwCyclesThisFrame >= dwClksPerFrame && !GetVideo().VideoGetVblBarEx(g_dwCyclesThisFrame))
|
|
{
|
|
#ifdef LOG_PERF_TIMINGS
|
|
PerfMarker perfMarkerVideoRefresh(g_timeVideoRefresh);
|
|
#endif
|
|
g_dwCyclesThisFrame -= dwClksPerFrame;
|
|
|
|
if (g_bFullSpeed)
|
|
GetFrame().VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame);
|
|
else
|
|
GetFrame().VideoPresentScreen(); // Just copy the output of our Apple framebuffer to the system Back Buffer
|
|
}
|
|
|
|
#ifdef LOG_PERF_TIMINGS
|
|
delete pPerfMarkerTotal; // Explicitly call dtor *before* SysClk_WaitTimer()
|
|
#endif
|
|
|
|
if ((g_nAppMode == MODE_RUNNING && !g_bFullSpeed) || bModeStepping_WaitTimer)
|
|
{
|
|
SysClk_WaitTimer();
|
|
}
|
|
}
|
|
|
|
void SingleStep(bool bReinit)
|
|
{
|
|
if (bReinit)
|
|
{
|
|
g_uModeStepping_Cycles = 0;
|
|
g_uModeStepping_LastGetKey_ScrollLock = false;
|
|
}
|
|
|
|
ContinueExecution();
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
void EnterMessageLoop(void)
|
|
{
|
|
MSG message;
|
|
|
|
PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE);
|
|
|
|
while (message.message!=WM_QUIT)
|
|
{
|
|
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&message);
|
|
DispatchMessage(&message);
|
|
|
|
while ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING))
|
|
{
|
|
if (PeekMessage(&message,0,0,0,PM_REMOVE))
|
|
{
|
|
if (message.message == WM_QUIT)
|
|
return;
|
|
|
|
TranslateMessage(&message);
|
|
DispatchMessage(&message);
|
|
}
|
|
else if (g_nAppMode == MODE_STEPPING)
|
|
{
|
|
DebugContinueStepping();
|
|
}
|
|
else
|
|
{
|
|
ContinueExecution();
|
|
if (g_nAppMode != MODE_DEBUG)
|
|
{
|
|
if (g_bFullSpeed)
|
|
ContinueExecution();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_nAppMode == MODE_DEBUG)
|
|
DebuggerUpdate();
|
|
else if (g_nAppMode == MODE_PAUSED)
|
|
Sleep(1); // Stop process hogging CPU - 1ms, as need to fade-out speaker sound buffer
|
|
else if (g_nAppMode == MODE_LOGO)
|
|
Sleep(1); // Stop process hogging CPU (NB. don't delay for too long otherwise key input can be slow in other apps - GH#569)
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
static void GetProgramDirectory(void)
|
|
{
|
|
char programDir[MAX_PATH];
|
|
GetModuleFileName((HINSTANCE)0, programDir, MAX_PATH);
|
|
programDir[MAX_PATH-1] = 0;
|
|
|
|
g_sProgramDir = programDir;
|
|
|
|
size_t loop = g_sProgramDir.size();
|
|
while (loop--)
|
|
{
|
|
if ((g_sProgramDir[loop] == PATH_SEPARATOR) || (g_sProgramDir[loop] == ':'))
|
|
{
|
|
g_sProgramDir.resize(loop + 1); // this reduces the size
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
void RegisterExtensions(void)
|
|
{
|
|
char szModuleFileName[MAX_PATH];
|
|
GetModuleFileName(static_cast<HMODULE>(NULL), szModuleFileName, sizeof(szModuleFileName));
|
|
|
|
// Wrap path & filename in quotes & null terminate
|
|
std::string command = std::string("\"") + szModuleFileName + '"';
|
|
|
|
std::string const icon = command + ",1";
|
|
|
|
command += " \"%1\""; // Append ' "%1"'
|
|
// command += " -d1 \"%1\""; // Append ' -d1 "%1"'
|
|
// command += " \"-d1 %1\""; // Append ' "-d1 %1"'
|
|
|
|
// NB. Registry access to HKLM typically results in ErrorCode 5(ACCESS DENIED), as UAC requires elevated permissions (Run as administrator).
|
|
// . HKEY_CLASSES_ROOT\CLSID is a merged view of HKLM\SOFTWARE\Classes and HKCU\SOFTWARE\Classes
|
|
|
|
// NB. Reflect extensions in DELREG.INF
|
|
// RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",0); // Removed as .bin is too generic
|
|
|
|
const char* pValueName = ".bin";
|
|
LSTATUS res = RegDeleteValue(HKEY_CLASSES_ROOT, pValueName);
|
|
if (res != NOERROR && res != ERROR_FILE_NOT_FOUND) LogFileOutput("RegDeleteValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = ".do";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT, pValueName ,REG_SZ,"DiskImage",0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = ".dsk";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT, pValueName, REG_SZ,"DiskImage",0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = ".nib";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT, pValueName, REG_SZ,"DiskImage",0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = ".po";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT, pValueName, REG_SZ,"DiskImage",0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = ".woz";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT, pValueName, REG_SZ,"DiskImage",0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
// RegSetValue(HKEY_CLASSES_ROOT,".2mg",REG_SZ,"DiskImage",0); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress)
|
|
// RegSetValue(HKEY_CLASSES_ROOT,".2img",REG_SZ,"DiskImage",0); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress)
|
|
// RegSetValue(HKEY_CLASSES_ROOT,".aws.yaml",REG_SZ,"DiskImage",0); // NB. Can't grab this extension (even though it returns 0!) with embedded period (and .yaml is too generic) - GH#548
|
|
// RegSetValue(HKEY_CLASSES_ROOT,".hdv",REG_SZ,"DiskImage",0); // TO DO
|
|
|
|
pValueName = "DiskImage";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, "Disk Image", 0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = "DiskImage\\DefaultIcon";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, icon.c_str(), 0);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
// This key can interfere....
|
|
// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExt\.dsk
|
|
|
|
pValueName = "DiskImage\\shell\\open\\command";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, command.c_str(), (uint32_t)(command.length() + 1));
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = "DiskImage\\shell\\open\\ddeexec";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, "%1", 3);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = "DiskImage\\shell\\open\\ddeexec\\application";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, "applewin", (uint32_t)(strlen("applewin") + 1));
|
|
// REG_SZ, szModuleFileName, strlen(szModuleFileName)+1);
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
|
|
pValueName = "DiskImage\\shell\\open\\ddeexec\\topic";
|
|
res = RegSetValue(HKEY_CLASSES_ROOT,
|
|
pValueName,
|
|
REG_SZ, "system", (uint32_t)(strlen("system") + 1));
|
|
if (res != NOERROR) LogFileOutput("RegSetValue(%s) failed (0x%08X)\n", pValueName, res);
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
// NB. On a restart, it's OK to call RegisterHotKey() again since the old g_hFrameWindow has been destroyed
|
|
static void RegisterHotKeys(void)
|
|
{
|
|
BOOL bStatus[3] = {0,0,0};
|
|
|
|
bStatus[0] = RegisterHotKey(
|
|
GetFrame().g_hFrameWindow , // HWND hWnd
|
|
VK_SNAPSHOT_560, // int id (user/custom id)
|
|
0 , // UINT fsModifiers
|
|
VK_SNAPSHOT // UINT vk = PrintScreen
|
|
);
|
|
|
|
bStatus[1] = RegisterHotKey(
|
|
GetFrame().g_hFrameWindow , // HWND hWnd
|
|
VK_SNAPSHOT_280, // int id (user/custom id)
|
|
MOD_SHIFT , // UINT fsModifiers
|
|
VK_SNAPSHOT // UINT vk = PrintScreen
|
|
);
|
|
|
|
bStatus[2] = RegisterHotKey(
|
|
GetFrame().g_hFrameWindow , // HWND hWnd
|
|
VK_SNAPSHOT_TEXT, // int id (user/custom id)
|
|
MOD_CONTROL , // UINT fsModifiers
|
|
VK_SNAPSHOT // UINT vk = PrintScreen
|
|
);
|
|
|
|
if ((!bStatus[0] || !bStatus[1] || !bStatus[2]))
|
|
{
|
|
std::string msg("Unable to register for PrintScreen key(s):\n");
|
|
|
|
if (!bStatus[0])
|
|
msg += "\n. PrintScreen";
|
|
if (!bStatus[1])
|
|
msg += "\n. Shift+PrintScreen";
|
|
if (!bStatus[2])
|
|
msg += "\n. Ctrl+PrintScreen";
|
|
|
|
if (GetFrame().GetShowPrintScreenWarningDialog())
|
|
SHMessageBoxCheck( GetFrame().g_hFrameWindow, msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK, MB_OK, "AppleWin-75097740-8e59-444c-bc94-2d4915132599" );
|
|
|
|
msg += "\n";
|
|
LogFileOutput(msg.c_str());
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void ExceptionHandler(const char* pError)
|
|
{
|
|
GetFrame().FrameMessageBox(
|
|
pError,
|
|
"Runtime Exception",
|
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
|
|
|
LogFileOutput("Runtime Exception: %s\n", pError);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void GetAppleWinVersion(void);
|
|
static void OneTimeInitialization(HINSTANCE passinstance);
|
|
static void RepeatInitialization(void);
|
|
static void Shutdown(void);
|
|
|
|
int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
|
|
{
|
|
char startDir[_MAX_PATH];
|
|
GetCurrentDirectory(sizeof(startDir), startDir);
|
|
g_sStartDir = startDir;
|
|
if (*(g_sStartDir.end()-1) != PATH_SEPARATOR) g_sStartDir += PATH_SEPARATOR;
|
|
|
|
if (!ProcessCmdLine(lpCmdLine))
|
|
return 0;
|
|
|
|
LogFileOutput("g_sStartDir = %s\n", g_sStartDir.c_str());
|
|
GetAppleWinVersion();
|
|
OneTimeInitialization(passinstance);
|
|
|
|
try
|
|
{
|
|
do
|
|
{
|
|
g_bRestart = false;
|
|
|
|
RepeatInitialization();
|
|
|
|
// ENTER THE MAIN MESSAGE LOOP
|
|
LogFileOutput("Main: EnterMessageLoop()\n");
|
|
EnterMessageLoop();
|
|
LogFileOutput("Main: LeaveMessageLoop()\n");
|
|
|
|
if (g_bRestart)
|
|
{
|
|
g_cmdLine.setFullScreen = g_bRestartFullScreen ? 1 : 0;
|
|
g_bRestartFullScreen = false;
|
|
|
|
CMouseInterface* pMouseCard = GetCardMgr().GetMouseCard();
|
|
if (pMouseCard)
|
|
{
|
|
// dtor removes event from g_SynchronousEventMgr - do before g_SynchronousEventMgr.Reset()
|
|
GetCardMgr().Remove( pMouseCard->GetSlot(), false );
|
|
LogFileOutput("Main: CMouseInterface::dtor\n");
|
|
}
|
|
|
|
_ASSERT(g_SynchronousEventMgr.GetHead() == NULL);
|
|
g_SynchronousEventMgr.Reset();
|
|
}
|
|
|
|
DSUninit();
|
|
LogFileOutput("Main: DSUninit()\n");
|
|
|
|
if (g_bHookSystemKey)
|
|
{
|
|
GetHookFilter().UninitHookThread();
|
|
LogFileOutput("Main: UnhookFilterForKeyboard()\n");
|
|
}
|
|
}
|
|
while (g_bRestart);
|
|
|
|
Shutdown();
|
|
}
|
|
catch (const std::exception& exception)
|
|
{
|
|
ExceptionHandler(exception.what());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void GetAppleWinVersion(void)
|
|
{
|
|
char szPath[_MAX_PATH];
|
|
|
|
if (0 == GetModuleFileName(NULL, szPath, sizeof(szPath)))
|
|
strcpy_s(szPath, sizeof(szPath), __argv[0]);
|
|
|
|
// Extract application version and store in a global variable
|
|
DWORD dwHandle, dwVerInfoSize;
|
|
|
|
dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle);
|
|
|
|
if (dwVerInfoSize > 0)
|
|
{
|
|
char* pVerInfoBlock = new char[dwVerInfoSize];
|
|
|
|
if (GetFileVersionInfo(szPath, NULL, dwVerInfoSize, pVerInfoBlock))
|
|
{
|
|
VS_FIXEDFILEINFO* pFixedFileInfo;
|
|
UINT pFixedFileInfoLen;
|
|
|
|
VerQueryValue(pVerInfoBlock, "\\", (LPVOID*) &pFixedFileInfo, (PUINT) &pFixedFileInfoLen);
|
|
|
|
// Construct version string from fixed file info block
|
|
|
|
UINT16 major = pFixedFileInfo->dwFileVersionMS >> 16;
|
|
UINT16 minor = pFixedFileInfo->dwFileVersionMS & 0xffff;
|
|
UINT16 fix = pFixedFileInfo->dwFileVersionLS >> 16;
|
|
UINT16 fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff;
|
|
SetAppleWinVersion(major, minor, fix, fix_minor);
|
|
}
|
|
|
|
delete [] pVerInfoBlock;
|
|
}
|
|
|
|
LogFileOutput("%s\n", GetAppleWinVersionAndBuild().c_str());
|
|
}
|
|
|
|
// DO ONE-TIME INITIALIZATION
|
|
static void OneTimeInitialization(HINSTANCE passinstance)
|
|
{
|
|
// Currently only support one RIFF file
|
|
if (!g_cmdLine.wavFileSpeaker.empty())
|
|
{
|
|
if (RiffInitWriteFile(g_cmdLine.wavFileSpeaker.c_str(), SPKR_SAMPLE_RATE, Spkr_GetNumChannels()))
|
|
Spkr_OutputToRiff();
|
|
}
|
|
else if (!g_cmdLine.wavFileMockingboard.empty())
|
|
{
|
|
if (RiffInitWriteFile(g_cmdLine.wavFileMockingboard.c_str(), MockingboardCard::SAMPLE_RATE, MockingboardCard::NUM_MB_CHANNELS))
|
|
GetCardMgr().GetMockingboardCardMgr().OutputToRiff();
|
|
}
|
|
|
|
// Initialize COM - so we can use CoCreateInstance
|
|
// . DSInit() & DIMouse::DirectInputInit are done when g_hFrameWindow is created (WM_CREATE)
|
|
// . DDInit() is done in RepeatInitialization() by GetVideo().Initialize()
|
|
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
LogFileOutput("Init: CoInitializeEx(), hr=0x%08X\n", hr);
|
|
|
|
g_bSysClkOK = SysClk_InitTimer();
|
|
LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", g_bSysClkOK ? 1:0);
|
|
#ifdef USE_SPEECH_API
|
|
if (g_bEnableSpeech)
|
|
{
|
|
const bool bSpeechOK = g_Speech.Init();
|
|
LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", bSpeechOK ? 1:0);
|
|
}
|
|
#endif
|
|
|
|
GetFrame().g_hInstance = passinstance;
|
|
GdiSetBatchLimit(512);
|
|
LogFileOutput("Init: GdiSetBatchLimit()\n");
|
|
|
|
GetProgramDirectory();
|
|
LogFileOutput("Init: GetProgramDirectory()\n");
|
|
|
|
if (g_bRegisterFileTypes)
|
|
{
|
|
RegisterExtensions();
|
|
LogFileOutput("Init: RegisterExtensions()\n");
|
|
}
|
|
|
|
Win32Frame::GetWin32Frame().FrameRegisterClass();
|
|
LogFileOutput("Init: FrameRegisterClass()\n");
|
|
}
|
|
|
|
// DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART
|
|
static void RepeatInitialization(void)
|
|
{
|
|
KeybReset();
|
|
GetVideo().SetVidHD(false); // Set true later (eg. by LoadConfiguration() or cmd-line) if VidHDCard is instantiated
|
|
ResetToLogoMode();
|
|
|
|
// NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video()
|
|
const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion
|
|
|
|
// Load configuration from Registry (+ will insert cards)
|
|
{
|
|
bool loadImages = g_cmdLine.szSnapshotName == NULL; // don't load floppy/harddisk images if a snapshot is to be loaded later on
|
|
LoadConfiguration(loadImages);
|
|
LogFileOutput("Main: LoadConfiguration()\n");
|
|
}
|
|
|
|
if (g_cmdLine.model != A2TYPE_MAX)
|
|
{
|
|
SetApple2Type(g_cmdLine.model);
|
|
GetPropertySheet().ConfigSaveApple2Type(g_cmdLine.model);
|
|
g_cmdLine.model = A2TYPE_MAX; // Don't reapply after a restart
|
|
}
|
|
|
|
RGB_SetVideocard(g_cmdLine.rgbCard, g_cmdLine.rgbCardForegroundColor, g_cmdLine.rgbCardBackgroundColor);
|
|
|
|
if (g_cmdLine.newVideoType >= 0)
|
|
{
|
|
GetVideo().SetVideoType( (VideoType_e)g_cmdLine.newVideoType );
|
|
g_cmdLine.newVideoType = -1; // Don't reapply after a restart
|
|
}
|
|
GetVideo().SetVideoStyle( (VideoStyle_e) ((GetVideo().GetVideoStyle() | g_cmdLine.newVideoStyleEnableMask) & ~g_cmdLine.newVideoStyleDisableMask) );
|
|
|
|
if (g_cmdLine.newVideoRefreshRate != VR_NONE)
|
|
{
|
|
GetVideo().SetVideoRefreshRate(g_cmdLine.newVideoRefreshRate);
|
|
g_cmdLine.newVideoRefreshRate = VR_NONE; // Don't reapply after a restart
|
|
SetCurrentCLK6502();
|
|
}
|
|
|
|
UseClockMultiplier(g_cmdLine.clockMultiplier);
|
|
g_cmdLine.clockMultiplier = 0.0;
|
|
|
|
// Apply the memory expansion switches after loading the Apple II machine type
|
|
if (IsApple2PlusOrClone(GetApple2Type()))
|
|
{
|
|
if (g_cmdLine.slotInfo[SLOT0].card == CT_Saturn128K)
|
|
{
|
|
Saturn128K::SetSaturnMemorySizeSlot0(g_cmdLine.uSaturnBanks); // Set number of banks before constructing Saturn card
|
|
SetExpansionMemType(CT_Saturn128K);
|
|
dynamic_cast<Saturn128K&>(GetCardMgr().GetRef(SLOT0)).SetSaturnMemorySize(g_cmdLine.uSaturnBanks);
|
|
}
|
|
else if (g_cmdLine.slotInfo[SLOT0].card == CT_LanguageCard)
|
|
{
|
|
SetExpansionMemType(CT_LanguageCard);
|
|
}
|
|
}
|
|
|
|
if (g_cmdLine.bSwapButtons0and1)
|
|
{
|
|
GetPropertySheet().SetButtonsSwapState(true);
|
|
// Reapply after a restart - TODO: grey-out the Config UI for "Swap 0/1" when this cmd line is passed in
|
|
}
|
|
|
|
JoyInitialize();
|
|
LogFileOutput("Main: JoyInitialize()\n");
|
|
|
|
// Init palette color
|
|
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideo().GetVideoType());
|
|
|
|
// Allow the slots to be configured as empty
|
|
// . remove all first, so that single-instance cards can can switch slots
|
|
// NB. this state is persisted to the Registry/conf.ini
|
|
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
|
{
|
|
if (g_cmdLine.slotInfo[i].card == CT_Empty)
|
|
GetCardMgr().Remove(i);
|
|
}
|
|
|
|
for (UINT i = SLOT0; i < NUM_SLOTS; i++)
|
|
{
|
|
if (g_cmdLine.slotInfo[i].card != CT_Empty && g_cmdLine.slotInfo[i].card != CT_Undefined)
|
|
{
|
|
if (GetCardMgr().QuerySlot(i) != g_cmdLine.slotInfo[i].card)
|
|
GetCardMgr().Insert(i, g_cmdLine.slotInfo[i].card);
|
|
}
|
|
|
|
g_cmdLine.slotInfo[i].card = CT_Undefined; // Don't reapply after a restart
|
|
}
|
|
|
|
if (g_cmdLine.supportDCD && GetCardMgr().IsSSCInstalled())
|
|
{
|
|
GetCardMgr().GetSSC()->SupportDCD(true);
|
|
}
|
|
|
|
if (g_cmdLine.enableDumpToRealPrinter && GetCardMgr().IsParallelPrinterCardInstalled())
|
|
{
|
|
GetCardMgr().GetParallelPrinterCard()->SetEnableDumpToRealPrinter(true);
|
|
}
|
|
|
|
for (UINT i = SLOT1; i < NUM_SLOTS; i++)
|
|
{
|
|
if (GetCardMgr().QuerySlot(i) == CT_Disk2 && g_cmdLine.slotInfo[i].isDiskII13)
|
|
{
|
|
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(i)).Set13SectorFirmware(true);
|
|
}
|
|
else if (GetCardMgr().QuerySlot(i) == CT_GenericHDD)
|
|
{
|
|
dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(i)).SetUserNumBlocks(g_cmdLine.uHarddiskNumBlocks);
|
|
if (g_cmdLine.useHdcFirmwareV1)
|
|
dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(i)).UseHdcFirmwareV1();
|
|
if (g_cmdLine.useHdcFirmwareV2)
|
|
dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(i)).UseHdcFirmwareV2();
|
|
if (g_cmdLine.slotInfo[i].useHdcFirmwareMode != HdcUndefinedFromCmdLine)
|
|
{
|
|
dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(i)).SetHdcFirmwareMode(g_cmdLine.slotInfo[i].useHdcFirmwareMode);
|
|
g_cmdLine.slotInfo[i].useHdcFirmwareMode = HdcUndefinedFromCmdLine; // Don't reapply after a restart
|
|
}
|
|
}
|
|
else if (GetCardMgr().GetMockingboardCardMgr().IsMockingboard(i))
|
|
{
|
|
if (g_cmdLine.slotInfo[i].useBad6522A)
|
|
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).UseBad6522A();
|
|
if (g_cmdLine.slotInfo[i].useBad6522B)
|
|
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).UseBad6522B();
|
|
for (UINT socket = 0; socket < NUM_SSI263; socket++)
|
|
{
|
|
const SSI263Type type = g_cmdLine.slotInfo[i].socketSSI263[socket];
|
|
if (type != SSI263Unknown)
|
|
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).SetSocketSSI263(socket, type);
|
|
}
|
|
const SSI263Type type = g_cmdLine.slotInfo[i].socketSC01;
|
|
if (type != SSI263Unknown)
|
|
dynamic_cast<MockingboardCard&>(GetCardMgr().GetRef(i)).SetSocketSC01(type);
|
|
}
|
|
}
|
|
|
|
// Aux slot
|
|
|
|
if (g_cmdLine.auxSlotCard != CT_Undefined)
|
|
{
|
|
if (g_cmdLine.auxSlotCard == CT_Empty)
|
|
{
|
|
GetCardMgr().RemoveAux();
|
|
SetExpansionMemType(CT_Empty);
|
|
}
|
|
else
|
|
{
|
|
if (GetCardMgr().QueryAux() != g_cmdLine.auxSlotCard) // Ignore if already got this card type in aux slot, ie. via LoadConfiguration()
|
|
{
|
|
GetCardMgr().InsertAux(g_cmdLine.auxSlotCard);
|
|
SetExpansionMemType(g_cmdLine.auxSlotCard);
|
|
}
|
|
|
|
#ifdef RAMWORKS
|
|
if (g_cmdLine.uRamWorksExPages)
|
|
{
|
|
_ASSERT(g_cmdLine.auxSlotCard == CT_RamWorksIII); // Implicitly set when using cmd line "-r banks"
|
|
SetRamWorksMemorySize(g_cmdLine.uRamWorksExPages);
|
|
g_cmdLine.uRamWorksExPages = 0; // Don't reapply after a restart
|
|
}
|
|
#endif
|
|
}
|
|
|
|
g_cmdLine.auxSlotCard = CT_Undefined; // Don't reapply after a restart
|
|
}
|
|
|
|
// Create window after inserting/removing VidHD card (as it affects width & height)
|
|
{
|
|
Win32Frame::GetWin32Frame().SetViewportScale(Win32Frame::GetWin32Frame().GetViewportScale(), true);
|
|
|
|
GetFrame().Initialize(true); // g_pFramebufferinfo been created now & COM init'ed
|
|
LogFileOutput("Main: VideoInitialize()\n");
|
|
|
|
LogFileOutput("Main: FrameCreateWindow() - pre\n");
|
|
Win32Frame::GetWin32Frame().FrameCreateWindow(); // GetFrame().g_hFrameWindow is now valid
|
|
LogFileOutput("Main: FrameCreateWindow() - post\n");
|
|
}
|
|
|
|
// Set best W,H resolution after inserting/removing VidHD card
|
|
if (g_cmdLine.bestFullScreenResolution || g_cmdLine.userSpecifiedWidth || g_cmdLine.userSpecifiedHeight)
|
|
{
|
|
bool res = false;
|
|
UINT bestWidth = 0, bestHeight = 0;
|
|
|
|
if (g_cmdLine.bestFullScreenResolution)
|
|
res = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight);
|
|
else
|
|
res = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight, g_cmdLine.userSpecifiedWidth, g_cmdLine.userSpecifiedHeight);
|
|
|
|
if (res)
|
|
LogFileOutput("Best resolution for -fs-width/height=x switch(es): Width=%d, Height=%d\n", bestWidth, bestHeight);
|
|
else
|
|
LogFileOutput("Failed to set parameter for -fs-width/height=x switch(es)\n");
|
|
|
|
if (res)
|
|
g_fullScreenResolutionChangedByUser = true;
|
|
}
|
|
|
|
// Pre: may need g_hFrameWindow for MessageBox errors
|
|
// Post: may enable HDC card, required for MemInitialize()->MemInitializeIO(); and may enable DiskII card
|
|
for (UINT i = SLOT1; i < NUM_SLOTS; i++)
|
|
{
|
|
bool temp = false;
|
|
InsertFloppyDisks(i, g_cmdLine.szImageName_drive[i], g_cmdLine.driveConnected[i], i == SLOT6 ? g_cmdLine.bBoot : temp);
|
|
g_cmdLine.szImageName_drive[i][DRIVE_1] = g_cmdLine.szImageName_drive[i][DRIVE_2] = NULL; // Don't insert on a restart
|
|
|
|
InsertHardDisks(i, g_cmdLine.szImageName_harddisk[i], i == SLOT7 ? g_cmdLine.bBoot : temp);
|
|
for (UINT j = HARDDISK_1; j < NUM_HARDDISKS; j++)
|
|
g_cmdLine.szImageName_harddisk[i][j] = NULL; // Don't insert on a restart
|
|
}
|
|
|
|
Snapshot_UpdatePath(); // If save-state's filename is a harddisk, and the floppy is in the same path, then the filename won't be updated
|
|
|
|
// Set *after* InsertFloppyDisks() & InsertHardDisks(), which both update g_sCurrentDir
|
|
if (!g_cmdLine.strCurrentDir.empty())
|
|
SetCurrentImageDir(g_cmdLine.strCurrentDir);
|
|
|
|
if (g_cmdLine.bRemoveNoSlotClock)
|
|
MemRemoveNoSlotClock();
|
|
|
|
if (g_cmdLine.supportExtraMBCardTypes)
|
|
GetCardMgr().GetMockingboardCardMgr().SetEnableExtraCardTypes(true);
|
|
|
|
if (g_cmdLine.noDisk2StepperDefer)
|
|
GetCardMgr().GetDisk2CardMgr().SetStepperDefer(false);
|
|
|
|
if (g_cmdLine.useAltCpuEmulation)
|
|
ForceAltCpuEmulation();
|
|
|
|
if (!g_cmdLine.debuggerAutoRunScriptFilename.empty())
|
|
DebugSetAutoRunScript(g_cmdLine.debuggerAutoRunScriptFilename);
|
|
|
|
// Call DebugInitialize() after SetCurrentImageDir()
|
|
DebugInitialize();
|
|
LogFileOutput("Main: DebugInitialize()\n");
|
|
|
|
MemInitialize();
|
|
LogFileOutput("Main: MemInitialize()\n");
|
|
|
|
// Show About dialog after creating main window (need g_hFrameWindow)
|
|
if (bShowAboutDlg)
|
|
{
|
|
if (!AboutDlg())
|
|
g_cmdLine.bShutdown = true; // Close everything down
|
|
else
|
|
RegSaveString(REG_CONFIG, REGVALUE_VERSION, true, g_VERSIONSTRING); // Only save version after user accepts license
|
|
}
|
|
|
|
if (g_bCapturePrintScreenKey)
|
|
{
|
|
RegisterHotKeys(); // needs valid g_hFrameWindow
|
|
LogFileOutput("Main: RegisterHotKeys()\n");
|
|
}
|
|
|
|
if (g_bHookSystemKey)
|
|
{
|
|
if (GetHookFilter().InitHookThread()) // needs valid g_hFrameWindow (for message pump)
|
|
LogFileOutput("Main: HookFilterForKeyboard()\n");
|
|
}
|
|
|
|
// Need to test if it's safe to call ResetMachineState(). In the meantime, just Reset() all cards:
|
|
// . Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor; and GH#515 (for HDCs)
|
|
GetCardMgr().Reset(true);
|
|
LogFileOutput("Main: GetCardMgr().Reset()\n");
|
|
|
|
if (!g_bSysClkOK)
|
|
{
|
|
GetFrame().FrameMessageBox("DirectX failed to create SystemClock instance", "AppleWin Error", MB_OK);
|
|
g_cmdLine.bShutdown = true;
|
|
}
|
|
|
|
if (g_bCustomRomF8Failed || g_bCustomRomFailed || (g_hCustomRomF8 != INVALID_HANDLE_VALUE && g_hCustomRom != INVALID_HANDLE_VALUE))
|
|
{
|
|
std::string msg = g_bCustomRomF8Failed ? "Failed to load custom F8 rom (not found or not exactly 2KiB)\n"
|
|
: g_bCustomRomFailed ? "Failed to load custom rom (not found or not exactly 12KiB or 16KiB)\n"
|
|
: "Unsupported -rom and -f8rom being used at the same time\n";
|
|
|
|
LogFileOutput("%s", msg.c_str());
|
|
GetFrame().FrameMessageBox(msg.c_str(), "AppleWin Error", MB_OK);
|
|
g_cmdLine.bShutdown = true;
|
|
}
|
|
|
|
if (g_cmdLine.szSnapshotName)
|
|
{
|
|
std::string strPathname(g_cmdLine.szSnapshotName);
|
|
size_t nIdx = strPathname.find_last_of(PATH_SEPARATOR);
|
|
if (nIdx >= 0 && nIdx+1 < (int)strPathname.length()) // path exists?
|
|
{
|
|
const std::string strPath = strPathname.substr(0, nIdx+1);
|
|
SetCurrentImageDir(strPath);
|
|
}
|
|
|
|
// Override value just loaded from Registry by LoadConfiguration()
|
|
// . NB. Registry value is not updated with this cmd-line value
|
|
Snapshot_SetFilename(g_cmdLine.szSnapshotName);
|
|
Snapshot_SetIgnoreHdcFirmware(g_cmdLine.snapshotIgnoreHdcFirmware);
|
|
Snapshot_LoadState();
|
|
g_cmdLine.bBoot = true;
|
|
g_cmdLine.szSnapshotName = NULL;
|
|
}
|
|
else
|
|
{
|
|
Snapshot_Startup(); // Do this after everything has been init'ed
|
|
LogFileOutput("Main: Snapshot_Startup()\n");
|
|
}
|
|
|
|
if (g_cmdLine.szScreenshotFilename)
|
|
{
|
|
GetFrame().Video_RedrawAndTakeScreenShot(g_cmdLine.szScreenshotFilename);
|
|
g_cmdLine.bShutdown = true;
|
|
}
|
|
|
|
if (g_cmdLine.bShutdown)
|
|
{
|
|
PostMessage(GetFrame().g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down
|
|
// NB. If shutting down, then don't post any other messages (GH#286)
|
|
}
|
|
else
|
|
{
|
|
if (g_cmdLine.setFullScreen > 0)
|
|
{
|
|
PostMessage(GetFrame().g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0);
|
|
g_cmdLine.setFullScreen = 0;
|
|
}
|
|
|
|
if (g_cmdLine.bBoot)
|
|
{
|
|
PostMessage(GetFrame().g_hFrameWindow, WM_USER_BOOT, 0, 0);
|
|
g_cmdLine.bBoot = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Shutdown(void)
|
|
{
|
|
// NB. WM_CLOSE has already called SetNormalMode() to exit full screen mode & restore default resolution
|
|
|
|
// Release COM
|
|
SysClk_UninitTimer();
|
|
LogFileOutput("Exit: SysClk_UninitTimer()\n");
|
|
|
|
CoUninitialize();
|
|
LogFileOutput("Exit: CoUninitialize()\n");
|
|
|
|
LogDone();
|
|
|
|
RiffFinishWriteFile();
|
|
|
|
if (g_hCustomRomF8 != INVALID_HANDLE_VALUE)
|
|
CloseHandle(g_hCustomRomF8);
|
|
|
|
if (g_hCustomRom != INVALID_HANDLE_VALUE)
|
|
CloseHandle(g_hCustomRom);
|
|
|
|
if (g_cmdLine.bSlot7EmptyOnExit)
|
|
GetCardMgr().Remove(SLOT7);
|
|
}
|
|
|
|
IPropertySheet& GetPropertySheet(void)
|
|
{
|
|
static CPropertySheet sg_PropertySheet;
|
|
return sg_PropertySheet;
|
|
}
|
|
|
|
FrameBase& GetFrame(void)
|
|
{
|
|
static Win32Frame sg_Win32Frame;
|
|
return sg_Win32Frame;
|
|
}
|
|
|
|
Video& GetVideo(void)
|
|
{
|
|
static Video video;
|
|
return video;
|
|
}
|