From bbe88da7879a97128b6bf44eb8c1bf523882a933 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 26 Nov 2020 21:50:06 +0000 Subject: [PATCH] AppleWin.cpp split (PR #875) . Split AppleWin -> Core with the functionality really needed by the emulator. . Split AppleWin -> Utilities for generic code not called by other emulator components. . Split AppleWin -> CmdLine for the command line option parsing. --- AppleWinExpress2008.vcproj | 28 +- AppleWinExpress2019.vcxproj | 10 +- AppleWinExpress2019.vcxproj.filters | 30 +- source/AY8910.cpp | 2 +- source/AppleWin.cpp | 2270 ------------------ source/CPU.cpp | 2 +- source/CardManager.cpp | 2 +- source/CmdLine.cpp | 527 ++++ source/CmdLine.h | 88 + source/Configuration/About.cpp | 3 +- source/Configuration/Config.h | 2 +- source/Configuration/PageConfig.cpp | 2 +- source/Configuration/PageDisk.cpp | 2 +- source/Configuration/PropertySheet.cpp | 2 +- source/Configuration/PropertySheetHelper.cpp | 2 +- source/Core.cpp | 300 +++ source/{AppleWin.h => Core.h} | 38 +- source/Debugger/Debug.cpp | 3 +- source/Debugger/Debugger_Assembler.cpp | 1 + source/Debugger/Debugger_Display.cpp | 3 +- source/Debugger/Debugger_Help.cpp | 2 +- source/Debugger/Debugger_Symbols.cpp | 3 +- source/Disk.cpp | 3 +- source/Disk2CardManager.cpp | 2 +- source/DiskImageHelper.cpp | 3 +- source/Harddisk.cpp | 3 +- source/Joystick.cpp | 2 +- source/Keyboard.cpp | 3 +- source/LanguageCard.cpp | 2 +- source/Memory.cpp | 2 +- source/Mockingboard.cpp | 2 +- source/MouseInterface.cpp | 2 +- source/NTSC.cpp | 2 +- source/NTSC_CharSet.cpp | 3 +- source/ParallelPrinter.cpp | 2 +- source/Pravets.cpp | 2 +- source/Registry.cpp | 3 +- source/SAM.cpp | 1 - source/SaveState.cpp | 2 +- source/SerialComms.cpp | 1 - source/SoundCore.cpp | 2 +- source/Speaker.cpp | 2 +- source/SynchronousEventManager.cpp | 1 - source/Tape.cpp | 1 - source/Utilities.cpp | 455 ++++ source/Utilities.h | 12 + source/Video.cpp | 2 +- source/Windows/AppleWin.cpp | 1048 ++++++++ source/Windows/AppleWin.h | 14 + source/Windows/WinFrame.cpp | 2 +- source/Windows/WinVideo.cpp | 3 +- source/Z80VICE/z80.cpp | 1 - source/z80emu.cpp | 1 - test/TestCPU6502/TestCPU6502.cpp | 2 +- 54 files changed, 2567 insertions(+), 2341 deletions(-) delete mode 100644 source/AppleWin.cpp create mode 100644 source/CmdLine.cpp create mode 100644 source/CmdLine.h create mode 100644 source/Core.cpp rename source/{AppleWin.h => Core.h} (70%) create mode 100644 source/Utilities.cpp create mode 100644 source/Utilities.h create mode 100644 source/Windows/AppleWin.cpp create mode 100644 source/Windows/AppleWin.h diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index f4caecb5..5b84393f 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -227,11 +227,27 @@ Filter=".cpp" > + + + + + + + + + + + + diff --git a/AppleWinExpress2019.vcxproj b/AppleWinExpress2019.vcxproj index c88598d7..07271ac3 100644 --- a/AppleWinExpress2019.vcxproj +++ b/AppleWinExpress2019.vcxproj @@ -22,10 +22,10 @@ - + @@ -45,6 +45,7 @@ + @@ -107,7 +108,9 @@ + + @@ -129,9 +132,9 @@ - + @@ -141,6 +144,7 @@ + @@ -214,7 +218,9 @@ NotUsing NotUsing + + diff --git a/AppleWinExpress2019.vcxproj.filters b/AppleWinExpress2019.vcxproj.filters index ec3295e5..3d7cfd4e 100644 --- a/AppleWinExpress2019.vcxproj.filters +++ b/AppleWinExpress2019.vcxproj.filters @@ -1,9 +1,6 @@  - - Source Files - Source Files\Emulator @@ -211,11 +208,20 @@ Source Files\Windows + + Source Files + + + Source Files + + + Source Files\Windows + + + Source Files + - - Source Files - Source Files\CommonVICE @@ -507,6 +513,18 @@ Source Files\Windows + + Source Files + + + Source Files + + + Source Files\Windows + + + Source Files + diff --git a/source/AY8910.cpp b/source/AY8910.cpp index 0b4e3338..3a0f0716 100644 --- a/source/AY8910.cpp +++ b/source/AY8910.cpp @@ -28,7 +28,7 @@ #include "AY8910.h" -#include "AppleWin.h" // For g_fh +#include "Core.h" // For g_fh #include "YamlHelper.h" /* The AY white noise RNG algorithm is based on info from MAME's ay8910.c - diff --git a/source/AppleWin.cpp b/source/AppleWin.cpp deleted file mode 100644 index 74099758..00000000 --- a/source/AppleWin.cpp +++ /dev/null @@ -1,2270 +0,0 @@ -/* -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 "AppleWin.h" -#include "CardManager.h" -#include "CPU.h" -#include "Debug.h" -#include "Disk.h" -#include "DiskImage.h" -#include "Harddisk.h" -#include "Joystick.h" -#include "Keyboard.h" -#include "LanguageCard.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 "SoundCore.h" -#include "Speaker.h" -#ifdef USE_SPEECH_API -#include "Speech.h" -#endif -#include "SynchronousEventManager.h" -#include "Windows/WinVideo.h" -#include "Windows/WinFrame.h" -#include "RGBMonitor.h" -#include "NTSC.h" - -#include "Configuration/About.h" -#include "Configuration/PropertySheet.h" -#include "Tfe/Tfe.h" - -static const UINT VERSIONSTRING_SIZE = 16; - -static UINT16 g_AppleWinVersion[4] = {0}; -static UINT16 g_OldAppleWinVersion[4] = {0}; -TCHAR VERSIONSTRING[VERSIONSTRING_SIZE] = "xx.yy.zz.ww"; - -std::string g_pAppTitle; - -eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; - -bool g_bFullSpeed = false; - -//================================================= - -// Win32 -HINSTANCE g_hInstance = (HINSTANCE)0; - -AppMode_e g_nAppMode = MODE_LOGO; -static bool g_bLoadedSaveState = false; -static bool g_bSysClkOK = false; - -std::string g_sStartDir; // NB. AppleWin.exe maybe relative to this! (GH#663) -std::string g_sProgramDir; // Directory of where AppleWin executable resides -std::string g_sDebugDir; // TODO: Not currently used -std::string g_sScreenShotDir; // TODO: Not currently used -std::string g_sConfigFile; // INI file to use instead of Registry - -bool g_bCapturePrintScreenKey = true; -static bool g_bHookSystemKey = true; -static bool g_bHookAltTab = false; -static bool g_bHookAltGrControl = false; - -std::string g_sCurrentDir; // Also Starting Dir. Debugger uses this when load/save -bool g_bRestart = false; -bool g_bRestartFullScreen = false; - -DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar -double g_fCurrentCLK6502 = CLK_6502_NTSC; // Affected by Config dialog's speed slider bar -static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar - -int g_nCpuCyclesFeedback = 0; -DWORD g_dwCyclesThisFrame = 0; - -bool g_bDisableDirectInput = false; -bool g_bDisableDirectSound = false; -bool g_bDisableDirectSoundMockingboard = false; -int g_nMemoryClearType = MIP_FF_FF_00_00; // Note: -1 = random MIP in Memory.cpp MemReset() - -IPropertySheet& sg_PropertySheet = * new CPropertySheet; - -SynchronousEventManager g_SynchronousEventMgr; - -HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom F8 ROM at $F800..$FFFF -static bool g_bCustomRomF8Failed = false; // Set if custom F8 ROM file failed -HANDLE g_hCustomRom = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $C000..$FFFF(16KiB) or $D000..$FFFF(12KiB) -static bool g_bCustomRomFailed = false; // Set if custom ROM file failed - -static bool g_bEnableSpeech = false; -#ifdef USE_SPEECH_API -CSpeech g_Speech; -#endif - -//=========================================================================== - -#ifdef LOG_PERF_TIMINGS -static UINT64 g_timeTotal = 0; -UINT64 g_timeCpu = 0; -UINT64 g_timeVideo = 0; // part of timeCpu -UINT64 g_timeMB_Timer = 0; // part of timeCpu -UINT64 g_timeMB_NoTimer = 0; -UINT64 g_timeSpeaker = 0; -static UINT64 g_timeVideoRefresh = 0; - -void LogPerfTimings(void) -{ - if (g_timeTotal) - { - UINT64 cpu = g_timeCpu - g_timeVideo - g_timeMB_Timer; - UINT64 video = g_timeVideo + g_timeVideoRefresh; - UINT64 spkr = g_timeSpeaker; - UINT64 mb = g_timeMB_Timer + g_timeMB_NoTimer; - UINT64 audio = spkr + mb; - UINT64 other = g_timeTotal - g_timeCpu - g_timeSpeaker - g_timeMB_NoTimer - g_timeVideoRefresh; - - LogOutput("Perf breakdown:\n"); - LogOutput(". CPU %% = %6.2f\n", (double)cpu / (double)g_timeTotal * 100.0); - LogOutput(". Video %% = %6.2f\n", (double)video / (double)g_timeTotal * 100.0); - LogOutput("... NTSC %% = %6.2f\n", (double)g_timeVideo / (double)g_timeTotal * 100.0); - LogOutput("... refresh %% = %6.2f\n", (double)g_timeVideoRefresh / (double)g_timeTotal * 100.0); - LogOutput(". Audio %% = %6.2f\n", (double)audio / (double)g_timeTotal * 100.0); - LogOutput("... Speaker %% = %6.2f\n", (double)spkr / (double)g_timeTotal * 100.0); - LogOutput("... MB %% = %6.2f\n", (double)mb / (double)g_timeTotal * 100.0); - LogOutput(". Other %% = %6.2f\n", (double)other / (double)g_timeTotal * 100.0); - LogOutput(". TOTAL %% = %6.2f\n", (double)(cpu+video+audio+other) / (double)g_timeTotal * 100.0); - } -} -#endif - -//=========================================================================== - -static DWORD dwLogKeyReadTickStart; -static bool bLogKeyReadDone = false; - -void LogFileTimeUntilFirstKeyReadReset(void) -{ -#ifdef LOG_PERF_TIMINGS - LogPerfTimings(); -#endif - - if (!g_fh) - return; - - dwLogKeyReadTickStart = GetTickCount(); - - bLogKeyReadDone = false; -} - -// Log the time from emulation restart/reboot until the first key read: BIT $C000 -// . AZTEC.DSK (DOS 3.3) does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message -// . Phasor1.dsk / ProDOS 1.1.1: PC=E797: B1 50: LDA ($50),Y / "Select an Option:" message -// . Rescue Raiders v1.3,v1.5: PC=895: LDA $C000 / boot to intro -void LogFileTimeUntilFirstKeyRead(void) -{ - if (!g_fh || bLogKeyReadDone) - return; - - if ( (mem[regs.pc-3] != 0x2C) // AZTEC: bit $c000 - && !((regs.pc-2) == 0xE797 && mem[regs.pc-2] == 0xB1 && mem[regs.pc-1] == 0x50) // Phasor1: lda ($50),y - && !((regs.pc-3) == 0x0895 && mem[regs.pc-3] == 0xAD) // Rescue Raiders v1.3,v1.5: lda $c000 - ) - return; - - DWORD dwTime = GetTickCount() - dwLogKeyReadTickStart; - - LogFileOutput("Time from emulation reboot until first $C000 access: %d msec\n", dwTime); - - bLogKeyReadDone = true; -} - -//--------------------------------------------------------------------------- - -eApple2Type GetApple2Type(void) -{ - return g_Apple2Type; -} - -void SetApple2Type(eApple2Type type) -{ - g_Apple2Type = type; - SetMainCpuDefault(type); -} - -const UINT16* GetOldAppleWinVersion(void) -{ - return g_OldAppleWinVersion; -} - -bool GetLoadedSaveStateFlag(void) -{ - return g_bLoadedSaveState; -} - -void SetLoadedSaveStateFlag(const bool bFlag) -{ - g_bLoadedSaveState = bFlag; -} - -bool GetHookAltGrControl(void) -{ - return g_bHookAltGrControl; -} - -CardManager& GetCardMgr(void) -{ - static CardManager g_CardMgr; // singleton - return g_CardMgr; -} - -static void ResetToLogoMode(void) -{ - g_nAppMode = MODE_LOGO; - 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 (sg_PropertySheet.GetScrollLockToggle()) - { - bScrollLock_FullSpeed = 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() && !MB_IsActive()) || - IsDebugSteppingAtFullSpeed(); - - if (g_bFullSpeed) - { - if (!bWasFullSpeed) - VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode - - // Don't call Spkr_Mute() - will get speaker clicks - MB_Mute(); - 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) - VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame); - - // Don't call Spkr_Demute() - MB_Demute(); - 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 DWORD uCyclesToExecute = (g_nAppMode == MODE_RUNNING) ? uCyclesToExecuteWithFeedback - /* MODE_STEPPING */ : 0; - - const bool bVideoUpdate = !g_bFullSpeed; - const DWORD uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate); - g_dwCyclesThisFrame += uActualCyclesExecuted; - - GetCardMgr().GetDisk2CardMgr().UpdateDriveState(uActualCyclesExecuted); - JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency - PrintUpdate(uActualCyclesExecuted); - MB_PeriodicUpdate(uActualCyclesExecuted); - - // - - DWORD 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 && !VideoGetVblBarEx(g_dwCyclesThisFrame)) - { -#ifdef LOG_PERF_TIMINGS - PerfMarker perfMarkerVideoRefresh(g_timeVideoRefresh); -#endif - g_dwCyclesThisFrame -= dwClksPerFrame; - - if (g_bFullSpeed) - VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame); - else - VideoRefreshScreen(); // 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(); -} - -//=========================================================================== - -double Get6502BaseClock(void) -{ - return (GetVideoRefreshRate() == VR_50HZ) ? CLK_6502_PAL : CLK_6502_NTSC; -} - -void UseClockMultiplier(double clockMultiplier) -{ - if (clockMultiplier == 0.0) - return; - - if (clockMultiplier < 1.0) - { - if (clockMultiplier < 0.5) - clockMultiplier = 0.5; - g_dwSpeed = (ULONG)((clockMultiplier - 0.5) * 20); // [0.5..0.9] -> [0..9] - } - else - { - g_dwSpeed = (ULONG)(clockMultiplier * 10); - if (g_dwSpeed >= SPEED_MAX) - g_dwSpeed = SPEED_MAX - 1; - } - - SetCurrentCLK6502(); -} - -void SetCurrentCLK6502(void) -{ - static DWORD dwPrevSpeed = (DWORD) -1; - static VideoRefreshRate_e prevVideoRefreshRate = VR_NONE; - - if (dwPrevSpeed == g_dwSpeed && GetVideoRefreshRate() == prevVideoRefreshRate) - return; - - dwPrevSpeed = g_dwSpeed; - prevVideoRefreshRate = GetVideoRefreshRate(); - - // SPEED_MIN = 0 = 0.50 MHz - // SPEED_NORMAL = 10 = 1.00 MHz - // 20 = 2.00 MHz - // SPEED_MAX-1 = 39 = 3.90 MHz - // SPEED_MAX = 40 = ???? MHz (run full-speed, /g_fCurrentCLK6502/ is ignored) - - if(g_dwSpeed < SPEED_NORMAL) - g_fMHz = 0.5 + (double)g_dwSpeed * 0.05; - else - g_fMHz = (double)g_dwSpeed / 10.0; - - g_fCurrentCLK6502 = Get6502BaseClock() * g_fMHz; - - // - // Now re-init modules that are dependent on /g_fCurrentCLK6502/ - // - - SpkrReinitialize(); - MB_Reinitialize(); -} - -//=========================================================================== - -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) -{ - TCHAR programDir[MAX_PATH]; - GetModuleFileName((HINSTANCE)0, programDir, MAX_PATH); - programDir[MAX_PATH-1] = 0; - - g_sProgramDir = programDir; - - int loop = g_sProgramDir.size(); - while (loop--) - { - if ((g_sProgramDir[loop] == TEXT('\\')) || (g_sProgramDir[loop] == TEXT(':'))) - { - g_sProgramDir.resize(loop + 1); // this reduces the size - break; - } - } -} - -//=========================================================================== - -// Backwards compatibility with AppleWin <1.24.0 -static void LoadConfigOldJoystick_v1(const UINT uJoyNum) -{ - DWORD dwOldJoyType; - if (!REGLOAD(TEXT(uJoyNum==0 ? REGVALUE_OLD_JOYSTICK0_EMU_TYPE1 : REGVALUE_OLD_JOYSTICK1_EMU_TYPE1), &dwOldJoyType)) - return; // EG. Old AppleWin never installed - - UINT uNewJoyType; - switch (dwOldJoyType) - { - case 0: // Disabled - default: - uNewJoyType = J0C_DISABLED; - break; - case 1: // PC Joystick - uNewJoyType = J0C_JOYSTICK1; - break; - case 2: // Keyboard (standard) - uNewJoyType = J0C_KEYBD_NUMPAD; - sg_PropertySheet.SetJoystickCenteringControl(JOYSTICK_MODE_FLOATING); - break; - case 3: // Keyboard (centering) - uNewJoyType = J0C_KEYBD_NUMPAD; - sg_PropertySheet.SetJoystickCenteringControl(JOYSTICK_MODE_CENTERING); - break; - case 4: // Mouse - uNewJoyType = J0C_MOUSE; - break; - } - - JoySetJoyType(uJoyNum, uNewJoyType); -} - -//Reads configuration from the registry entries -void LoadConfiguration(void) -{ - DWORD dwComputerType = 0; - eApple2Type apple2Type = A2TYPE_APPLE2EENHANCED; - - if (REGLOAD(TEXT(REGVALUE_APPLE2_TYPE), &dwComputerType)) - { - const DWORD dwLoadedComputerType = dwComputerType; - - if ( (dwComputerType >= A2TYPE_MAX) || - (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE) || - (dwComputerType >= A2TYPE_CLONE_A2_MAX && dwComputerType < A2TYPE_CLONE_A2E) ) - dwComputerType = A2TYPE_APPLE2EENHANCED; - - // Remap the bad Pravets models (before AppleWin v1.26) - if (dwComputerType == A2TYPE_BAD_PRAVETS82) dwComputerType = A2TYPE_PRAVETS82; - if (dwComputerType == A2TYPE_BAD_PRAVETS8M) dwComputerType = A2TYPE_PRAVETS8M; - - // Remap the bad Pravets models (at AppleWin v1.26) - GH#415 - if (dwComputerType == A2TYPE_CLONE) dwComputerType = A2TYPE_PRAVETS82; - - if (dwLoadedComputerType != dwComputerType) - { - char sText[100]; - StringCbPrintf(sText, sizeof(sText), "Unsupported Apple2Type(%d). Changing to %d", dwLoadedComputerType, dwComputerType); - - LogFileOutput("%s\n", sText); - - MessageBox( - GetDesktopWindow(), // NB. g_hFrameWindow is not yet valid - sText, - "Load Configuration", - MB_ICONSTOP | MB_SETFOREGROUND); - - sg_PropertySheet.ConfigSaveApple2Type((eApple2Type)dwComputerType); - } - - apple2Type = (eApple2Type) dwComputerType; - } - else if (REGLOAD(TEXT(REGVALUE_OLD_APPLE2_TYPE), &dwComputerType)) // Support older AppleWin registry entries - { - switch (dwComputerType) - { - // NB. No A2TYPE_APPLE2E (this is correct) - case 0: apple2Type = A2TYPE_APPLE2; break; - case 1: apple2Type = A2TYPE_APPLE2PLUS; break; - case 2: apple2Type = A2TYPE_APPLE2EENHANCED; break; - default: apple2Type = A2TYPE_APPLE2EENHANCED; break; - } - } - - SetApple2Type(apple2Type); - - // - - DWORD dwMainCpuType; - REGLOAD_DEFAULT(TEXT(REGVALUE_CPU_TYPE), &dwMainCpuType, CPU_65C02); - if (dwMainCpuType != CPU_6502 && dwMainCpuType != CPU_65C02) - dwMainCpuType = CPU_65C02; - SetMainCpu((eCpuType)dwMainCpuType); - - // - - DWORD dwJoyType; - if (REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &dwJoyType)) - JoySetJoyType(JN_JOYSTICK0, dwJoyType); - else if (REGLOAD(TEXT(REGVALUE_OLD_JOYSTICK0_EMU_TYPE2), &dwJoyType)) // GH#434 - JoySetJoyType(JN_JOYSTICK0, dwJoyType); - else - LoadConfigOldJoystick_v1(JN_JOYSTICK0); - - if (REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &dwJoyType)) - JoySetJoyType(JN_JOYSTICK1, dwJoyType); - else if (REGLOAD(TEXT(REGVALUE_OLD_JOYSTICK1_EMU_TYPE2), &dwJoyType)) // GH#434 - JoySetJoyType(JN_JOYSTICK1, dwJoyType); - else - LoadConfigOldJoystick_v1(JN_JOYSTICK1); - - DWORD dwSoundType; - REGLOAD_DEFAULT(TEXT(REGVALUE_SOUND_EMULATION), &dwSoundType, REG_SOUNDTYPE_WAVE); - switch (dwSoundType) - { - case REG_SOUNDTYPE_NONE: - case REG_SOUNDTYPE_DIRECT: // Not supported from 1.26 - case REG_SOUNDTYPE_SMART: // Not supported from 1.26 - default: - soundtype = SOUND_NONE; - break; - case REG_SOUNDTYPE_WAVE: - soundtype = SOUND_WAVE; - break; - } - - TCHAR serialPortName[CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM]; - if (RegLoadString( - TEXT(REG_CONFIG), - TEXT(REGVALUE_SERIAL_PORT_NAME), - TRUE, - serialPortName, - CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM)) - { - if (GetCardMgr().IsSSCInstalled()) - GetCardMgr().GetSSC()->SetSerialPortName(serialPortName); - } - - REGLOAD_DEFAULT(TEXT(REGVALUE_EMULATION_SPEED), &g_dwSpeed, SPEED_NORMAL); - Config_Load_Video(); - SetCurrentCLK6502(); // Pre: g_dwSpeed && Config_Load_Video()->SetVideoRefreshRate() - - DWORD dwEnhanceDisk; - REGLOAD_DEFAULT(TEXT(REGVALUE_ENHANCE_DISK_SPEED), &dwEnhanceDisk, 1); - GetCardMgr().GetDisk2CardMgr().SetEnhanceDisk(dwEnhanceDisk ? true : false); - - // - - DWORD dwTmp = 0; - - if(REGLOAD(TEXT(REGVALUE_FS_SHOW_SUBUNIT_STATUS), &dwTmp)) - SetFullScreenShowSubunitStatus(dwTmp ? true : false); - - if(REGLOAD(TEXT(REGVALUE_THE_FREEZES_F8_ROM), &dwTmp)) - sg_PropertySheet.SetTheFreezesF8Rom(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp)) - SpkrSetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); - - if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp)) - MB_SetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); - - if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp)) - g_bSaveStateOnExit = dwTmp ? true : false; - - - if(REGLOAD(TEXT(REGVALUE_DUMP_TO_PRINTER), &dwTmp)) - g_bDumpToPrinter = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_CONVERT_ENCODING), &dwTmp)) - g_bConvertEncoding = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_FILTER_UNPRINTABLE), &dwTmp)) - g_bFilterUnprintable = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_PRINTER_APPEND), &dwTmp)) - g_bPrinterAppend = dwTmp ? true : false; - - - if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) // TODO: Change to REGVALUE_SLOT7 - HD_SetEnabled(dwTmp ? true : false); - - if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) - JoySetTrim((short)dwTmp, true); - if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) - JoySetTrim((short)dwTmp, false); - - if(REGLOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp)) - sg_PropertySheet.SetScrollLockToggle(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_CURSOR_CONTROL), &dwTmp)) - sg_PropertySheet.SetJoystickCursorControl(dwTmp); - if(REGLOAD(TEXT(REGVALUE_AUTOFIRE), &dwTmp)) - sg_PropertySheet.SetAutofire(dwTmp); - if(REGLOAD(TEXT(REGVALUE_SWAP_BUTTONS_0_AND_1), &dwTmp)) - sg_PropertySheet.SetButtonsSwapState(dwTmp ? true : false); - if(REGLOAD(TEXT(REGVALUE_CENTERING_CONTROL), &dwTmp)) - sg_PropertySheet.SetJoystickCenteringControl(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_MOUSE_CROSSHAIR), &dwTmp)) - sg_PropertySheet.SetMouseShowCrosshair(dwTmp); - if(REGLOAD(TEXT(REGVALUE_MOUSE_RESTRICT_TO_WINDOW), &dwTmp)) - sg_PropertySheet.SetMouseRestrictToWindow(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp)) - GetCardMgr().Insert(4, (SS_CARDTYPE)dwTmp); - if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp)) - GetCardMgr().Insert(5, (SS_CARDTYPE)dwTmp); - - // - - TCHAR szFilename[MAX_PATH]; - - // Load save-state pathname *before* inserting any harddisk/disk images (for both init & reinit cases) - // NB. inserting harddisk/disk can change snapshot pathname - RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_SAVESTATE_FILENAME), 1, szFilename, MAX_PATH, TEXT("")); // Can be pathname or just filename - Snapshot_SetFilename(szFilename); // If not in Registry than default will be used (ie. g_sCurrentDir + default filename) - - // - - RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szFilename, MAX_PATH, TEXT("")); - if (szFilename[0] == '\0') - GetCurrentDirectory(sizeof(szFilename), szFilename); - SetCurrentImageDir(szFilename); - - HD_LoadLastDiskImage(HARDDISK_1); - HD_LoadLastDiskImage(HARDDISK_2); - - // - - // Current/Starting Dir is the "root" of where the user keeps their disk images - RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH, TEXT("")); - if (szFilename[0] == '\0') - GetCurrentDirectory(sizeof(szFilename), szFilename); - SetCurrentImageDir(szFilename); - - GetCardMgr().GetDisk2CardMgr().LoadLastDiskImage(); - - // - - DWORD dwTfeEnabled; - REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &dwTfeEnabled, 0); - tfe_enabled = dwTfeEnabled ? 1 : 0; - - RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT("")); - update_tfe_interface(szFilename, NULL); - - // - - RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_PRINTER_FILENAME), 1, szFilename, MAX_PATH, TEXT("")); - Printer_SetFilename(szFilename); // If not in Registry than default will be used - - REGLOAD_DEFAULT(TEXT(REGVALUE_PRINTER_IDLE_LIMIT), &dwTmp, 10); - Printer_SetIdleLimit(dwTmp); - - if (REGLOAD(TEXT(REGVALUE_WINDOW_SCALE), &dwTmp)) - SetViewportScale(dwTmp); - - if (REGLOAD(TEXT(REGVALUE_CONFIRM_REBOOT), &dwTmp)) - g_bConfirmReboot = dwTmp; -} - -//=========================================================================== - -bool SetCurrentImageDir(const std::string & pszImageDir) -{ - g_sCurrentDir = pszImageDir; - - if (!g_sCurrentDir.empty() && *g_sCurrentDir.rbegin() != '\\') - g_sCurrentDir += '\\'; - - if( SetCurrentDirectory(g_sCurrentDir.c_str()) ) - return true; - - return false; -} - -//=========================================================================== - -// TODO: Added dialog option of which file extensions to registry -static bool g_bRegisterFileTypes = true; - - -void RegisterExtensions(void) -{ - TCHAR szCommandTmp[MAX_PATH]; - GetModuleFileName((HMODULE)0,szCommandTmp,MAX_PATH); - - TCHAR command[MAX_PATH]; - wsprintf(command, "\"%s\"", szCommandTmp); // Wrap path & filename in quotes & null terminate - - TCHAR icon[MAX_PATH]; - wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command); - - _tcscat(command,TEXT(" \"%1\"")); // Append "%1" -// _tcscat(command,TEXT("-d1 %1\"")); // Append "%1" -// sprintf(command, "\"%s\" \"-d1 %%1\"", szCommandTmp); // Wrap path & filename in quotes & null terminate - - // 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,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,_tcslen(command)+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",_tcslen("applewin")+1); -// REG_SZ,szCommandTmp,_tcslen(szCommandTmp)+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",_tcslen("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( - g_hFrameWindow , // HWND hWnd - VK_SNAPSHOT_560, // int id (user/custom id) - 0 , // UINT fsModifiers - VK_SNAPSHOT // UINT vk = PrintScreen - ); - - bStatus[1] = RegisterHotKey( - g_hFrameWindow , // HWND hWnd - VK_SNAPSHOT_280, // int id (user/custom id) - MOD_SHIFT , // UINT fsModifiers - VK_SNAPSHOT // UINT vk = PrintScreen - ); - - bStatus[2] = RegisterHotKey( - 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 (g_bShowPrintScreenWarningDialog) - MessageBox( g_hFrameWindow, msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK ); - - msg += "\n"; - LogFileOutput(msg.c_str()); - } -} - -//--------------------------------------------------------------------------- - -static HINSTANCE g_hinstDLL = 0; -static HHOOK g_hhook = 0; - -static HANDLE g_hHookThread = NULL; -static DWORD g_HookThreadId = 0; - -// Pre: g_hFrameWindow must be valid -static bool HookFilterForKeyboard() -{ - g_hinstDLL = LoadLibrary(TEXT("HookFilter.dll")); - - _ASSERT(g_hFrameWindow); - - typedef void (*RegisterHWNDProc)(HWND, bool, bool); - RegisterHWNDProc RegisterHWND = (RegisterHWNDProc) GetProcAddress(g_hinstDLL, "RegisterHWND"); - if (RegisterHWND) - RegisterHWND(g_hFrameWindow, g_bHookAltTab, g_bHookAltGrControl); - - HOOKPROC hkprcLowLevelKeyboardProc = (HOOKPROC) GetProcAddress(g_hinstDLL, "LowLevelKeyboardProc"); - - g_hhook = SetWindowsHookEx( - WH_KEYBOARD_LL, - hkprcLowLevelKeyboardProc, - g_hinstDLL, - 0); - - if (g_hhook != 0 && g_hFrameWindow != 0) - return true; - - std::string msg("Failed to install hook filter for system keys"); - - DWORD dwErr = GetLastError(); - MessageBox(GetDesktopWindow(), msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK); - - msg += "\n"; - LogFileOutput(msg.c_str()); - return false; -} - -static void UnhookFilterForKeyboard() -{ - UnhookWindowsHookEx(g_hhook); - FreeLibrary(g_hinstDLL); -} - -static DWORD WINAPI HookThread(LPVOID lpParameter) -{ - if (!HookFilterForKeyboard()) - return -1; - - MSG msg; - while(GetMessage(&msg, NULL, 0, 0) > 0) - { - if (msg.message == WM_QUIT) - break; - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - UnhookFilterForKeyboard(); - return 0; -} - -static bool InitHookThread() -{ - g_hHookThread = CreateThread(NULL, // lpThreadAttributes - 0, // dwStackSize - (LPTHREAD_START_ROUTINE) HookThread, - 0, // lpParameter - 0, // dwCreationFlags : 0 = Run immediately - &g_HookThreadId); // lpThreadId - if (g_hHookThread == NULL) - return false; - - return true; -} - -static void UninitHookThread() -{ - if (g_hHookThread) - { - if (!PostThreadMessage(g_HookThreadId, WM_QUIT, 0, 0)) - { - _ASSERT(0); - return; - } - - do - { - DWORD dwExitCode; - if (GetExitCodeThread(g_hHookThread, &dwExitCode)) - { - if(dwExitCode == STILL_ACTIVE) - Sleep(10); - else - break; - } - } - while(1); - - CloseHandle(g_hHookThread); - g_hHookThread = NULL; - g_HookThreadId = 0; - } -} - -//=========================================================================== - -LPSTR GetCurrArg(LPSTR lpCmdLine) -{ - if(*lpCmdLine == '\"') - lpCmdLine++; - - return lpCmdLine; -} - -LPSTR GetNextArg(LPSTR lpCmdLine) -{ - int bInQuotes = 0; - - while(*lpCmdLine) - { - if(*lpCmdLine == '\"') - { - bInQuotes ^= 1; - if(!bInQuotes) - { - *lpCmdLine++ = 0x00; // Assume end-quote is end of this arg - continue; - } - } - - if((*lpCmdLine == ' ') && !bInQuotes) - { - *lpCmdLine++ = 0x00; - break; - } - - lpCmdLine++; - } - - return lpCmdLine; -} - -//--------------------------------------------------------------------------- - -static std::string GetFullPath(LPCSTR szFileName) -{ - std::string strPathName; - - if (szFileName[0] == '\\' || szFileName[1] == ':') - { - // Abs pathname - strPathName = szFileName; - } - else - { - // Rel pathname (GH#663) - strPathName = g_sStartDir; - strPathName.append(szFileName); - } - - return strPathName; -} - -static void SetCurrentDir(std::string pathname) -{ - // Due to the order HDDs/disks are inserted, then s7 insertions take priority over s6 & s5; and d2 takes priority over d1: - // . if -s6[dN] and -hN are specified, then g_sCurrentDir will be set to the HDD image's path - // . if -s5[dN] and -s6[dN] are specified, then g_sCurrentDir will be set to the s6 image's path - // . if -[sN]d1 and -[sN]d2 are specified, then g_sCurrentDir will be set to the d2 image's path - // This is purely dependent on the current order of InsertFloppyDisks() & InsertHardDisks() - ie. very brittle! - // . better to use -current-dir to be explicit - std::size_t found = pathname.find_last_of("\\"); - std::string path = pathname.substr(0, found); - SetCurrentImageDir(path); -} - -static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName) -{ - Disk2InterfaceCard& disk2Card = dynamic_cast(GetCardMgr().GetRef(slot)); - - if (szFileName[0] == '\0') - { - disk2Card.EjectDisk(nDrive); - return true; - } - - std::string strPathName = GetFullPath(szFileName); - if (strPathName.empty()) return false; - - ImageError_e Error = disk2Card.InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); - bool res = (Error == eIMAGE_ERROR_NONE); - if (res) - SetCurrentDir(strPathName); - return res; -} - -static bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName) -{ - if (szFileName[0] == '\0') - { - HD_Unplug(nDrive); - return true; - } - - std::string strPathName = GetFullPath(szFileName); - if (strPathName.empty()) return false; - - BOOL bRes = HD_Insert(nDrive, strPathName.c_str()); - bool res = (bRes == TRUE); - if (res) - SetCurrentDir(strPathName); - return res; -} - -static void InsertFloppyDisks(const UINT slot, LPSTR szImageName_drive[NUM_DRIVES], bool& bBoot) -{ - _ASSERT(slot == 5 || slot == 6); - - if (!szImageName_drive[DRIVE_1] && !szImageName_drive[DRIVE_2]) - return; - - bool bRes = true; - - if (szImageName_drive[DRIVE_1]) - { - bRes = DoDiskInsert(slot, DRIVE_1, szImageName_drive[DRIVE_1]); - LogFileOutput("Init: S%d, DoDiskInsert(D1), res=%d\n", slot, bRes); - FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); // floppy activity LEDs and floppy buttons - bBoot = true; - } - - if (szImageName_drive[DRIVE_2]) - { - bRes |= DoDiskInsert(slot, DRIVE_2, szImageName_drive[DRIVE_2]); - LogFileOutput("Init: S%d, DoDiskInsert(D2), res=%d\n", slot, bRes); - } - - if (!bRes) - MessageBox(g_hFrameWindow, "Failed to insert floppy disk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK); -} - -static void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBoot) -{ - if (!szImageName_harddisk[HARDDISK_1] && !szImageName_harddisk[HARDDISK_2]) - return; - - // Enable the Harddisk controller card - - HD_SetEnabled(true); - - DWORD dwTmp; - BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); - if (!res || !dwTmp) - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled - - // - - bool bRes = true; - - if (szImageName_harddisk[HARDDISK_1]) - { - bRes = DoHardDiskInsert(HARDDISK_1, szImageName_harddisk[HARDDISK_1]); - LogFileOutput("Init: DoHardDiskInsert(HDD1), res=%d\n", bRes); - FrameRefreshStatus(DRAW_LEDS); // harddisk activity LED - bBoot = true; - } - - if (szImageName_harddisk[HARDDISK_2]) - { - bRes |= DoHardDiskInsert(HARDDISK_2, szImageName_harddisk[HARDDISK_2]); - LogFileOutput("Init: DoHardDiskInsert(HDD2), res=%d\n", bRes); - } - - if (!bRes) - MessageBox(g_hFrameWindow, "Failed to insert harddisk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK); -} - -static void UnplugHardDiskControllerCard(void) -{ - HD_SetEnabled(false); - - DWORD dwTmp; - BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); - if (!res || dwTmp) - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled -} - -static bool CheckOldAppleWinVersion(void) -{ - TCHAR szOldAppleWinVersion[VERSIONSTRING_SIZE + 1]; - RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, VERSIONSTRING_SIZE, TEXT("")); - const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0; - - // version: xx.yy.zz.ww - char* p0 = szOldAppleWinVersion; - int len = strlen(szOldAppleWinVersion); - szOldAppleWinVersion[len] = '.'; // append a null terminator - szOldAppleWinVersion[len + 1] = '\0'; - for (UINT i=0; i<4; i++) - { - char* p1 = strstr(p0, "."); - if (!p1) - break; - *p1 = 0; - g_OldAppleWinVersion[i] = atoi(p0); - p0 = p1+1; - } - - return bShowAboutDlg; -} - -//--------------------------------------------------------------------------- - -static void ExceptionHandler(const char* pError) -{ - MessageBox( g_hFrameWindow, - pError, - TEXT("Runtime Exception"), - MB_ICONEXCLAMATION | MB_SETFOREGROUND); - - LogFileOutput("Runtime Exception: %s\n", pError); -} - -//--------------------------------------------------------------------------- - -static bool ProcessCmdLine(LPSTR lpCmdLine); -static void GetAppleWinVersion(void); -static void OneTimeInitialization(HINSTANCE passinstance); -static void RepeatInitialization(void); -static void Shutdown(void); - -struct CmdLine -{ - CmdLine() - { - bShutdown = false; - bSetFullScreen = false; - bBoot = false; - bChangedDisplayResolution = false; - bSlot0LanguageCard = false; - bSlot7EmptyOnExit = false; - bSwapButtons0and1 = false; - bRemoveNoSlotClock = false; - bestWidth = 0; - bestHeight = 0; - szImageName_harddisk[HARDDISK_1] = NULL; - szImageName_harddisk[HARDDISK_2] = NULL; - szSnapshotName = NULL; - szScreenshotFilename = NULL; - uRamWorksExPages = 0; - uSaturnBanks = 0; - newVideoType = -1; - newVideoStyleEnableMask = 0; - newVideoStyleDisableMask = 0; - newVideoRefreshRate = VR_NONE; - clockMultiplier = 0.0; // 0 => not set from cmd-line - model = A2TYPE_MAX; - rgbCard = RGB_Videocard_e::Apple; - rgbCardForegroundColor = 15; - rgbCardBackgroundColor = 0; - - for (UINT i = 0; i < NUM_SLOTS; i++) - { - bSlotEmpty[i] = false; - slotInsert[i] = CT_Empty; - szImageName_drive[i][DRIVE_1] = NULL; - szImageName_drive[i][DRIVE_2] = NULL; - } - } - - bool bShutdown; - bool bSetFullScreen; - bool bBoot; - bool bChangedDisplayResolution; - bool bSlot0LanguageCard; - bool bSlotEmpty[NUM_SLOTS]; - bool bSlot7EmptyOnExit; - bool bSwapButtons0and1; - bool bRemoveNoSlotClock; - SS_CARDTYPE slotInsert[NUM_SLOTS]; - UINT bestWidth; - UINT bestHeight; - LPSTR szImageName_drive[NUM_SLOTS][NUM_DRIVES]; - LPSTR szImageName_harddisk[NUM_HARDDISKS]; - LPSTR szSnapshotName; - LPSTR szScreenshotFilename; - UINT uRamWorksExPages; - UINT uSaturnBanks; - int newVideoType; - int newVideoStyleEnableMask; - int newVideoStyleDisableMask; - VideoRefreshRate_e newVideoRefreshRate; - double clockMultiplier; - eApple2Type model; - RGB_Videocard_e rgbCard; - int rgbCardForegroundColor; - int rgbCardBackgroundColor; - std::string strCurrentDir; -}; - -static CmdLine g_cmdLine; - -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) != '\\') g_sStartDir += '\\'; - - 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.bSetFullScreen = g_bRestartFullScreen; - g_bRestartFullScreen = false; - } - - MB_Reset(); - LogFileOutput("Main: MB_Reset()\n"); - - CMouseInterface* pMouseCard = GetCardMgr().GetMouseCard(); - if (pMouseCard) - { - pMouseCard->Reset(); // Deassert any pending IRQs - GH#514 - LogFileOutput("Main: CMouseInterface::Uninitialize()\n"); - } - - DSUninit(); - LogFileOutput("Main: DSUninit()\n"); - - if (g_bRestart) - g_SynchronousEventMgr.Reset(); - - if (g_bHookSystemKey) - { - UninitHookThread(); - LogFileOutput("Main: UnhookFilterForKeyboard()\n"); - } - } - while (g_bRestart); - } - catch(std::runtime_error exception) - { - ExceptionHandler(exception.what()); - } - catch(std::exception exception) - { - ExceptionHandler(exception.what()); - } - - Shutdown(); - return 0; -} - -static bool ProcessCmdLine(LPSTR lpCmdLine) -{ - const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput - std::string strUnsupported; - - // If 1st param looks like an abs pathname then assume that an associated filetype has been double-clicked - // NB. Handled by WM_DDE_INITIATE & WM_DDE_EXECUTE msgs - if ((lpCmdLine[0] >= '\"' && lpCmdLine[1] >= 'A' && lpCmdLine[1] <= 'Z' && lpCmdLine[2] == ':') // always in quotes - || strncmp("\\\\?\\", lpCmdLine, 4) == 0) - return true; - - while (*lpCmdLine) - { - LPSTR lpNextArg = GetNextArg(lpCmdLine); - - if (((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL)) - { - LogInit(); - } - else if (strcmp(lpCmdLine, "-noreg") == 0) - { - g_bRegisterFileTypes = false; - } - else if (strcmp(lpCmdLine, "-conf") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - char buf[MAX_PATH]; - DWORD res = GetFullPathName(lpCmdLine, MAX_PATH, buf, NULL); - if (res == 0) - LogFileOutput("Failed to open configuration file: %s\n", lpCmdLine); - else - g_sConfigFile = buf; - } - else if (strcmp(lpCmdLine, "-d1") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szImageName_drive[SLOT6][DRIVE_1] = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-d2") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szImageName_drive[SLOT6][DRIVE_2] = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-h1") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szImageName_harddisk[HARDDISK_1] = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-h2") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szImageName_harddisk[HARDDISK_2] = lpCmdLine; - } - else if (lpCmdLine[0] == '-' && lpCmdLine[1] == 's' && lpCmdLine[2] >= '1' && lpCmdLine[2] <= '7') - { - const UINT slot = lpCmdLine[2] - '0'; - - if (lpCmdLine[3] == 0) // -s[1..7] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - if (strcmp(lpCmdLine, "empty") == 0) - g_cmdLine.bSlotEmpty[slot] = true; - if (strcmp(lpCmdLine, "diskii") == 0) - g_cmdLine.slotInsert[slot] = CT_Disk2; - } - else if (lpCmdLine[3] == 'd' && (lpCmdLine[4] == '1' || lpCmdLine[4] == '2')) // -s[1..7]d[1|2] - { - const UINT drive = lpCmdLine[4] == '1' ? DRIVE_1 : DRIVE_2; - - if (slot != 5 && slot != 6) - { - LogFileOutput("Unsupported arg: %s\n", lpCmdLine); - } - else - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szImageName_drive[slot][drive] = lpCmdLine; - } - } - else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0) - { - g_cmdLine.bSlot7EmptyOnExit = true; - } - else - { - LogFileOutput("Unsupported arg: %s\n", lpCmdLine); - } - } - else if (strcmp(lpCmdLine, "-load-state") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.szSnapshotName = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-f") == 0) - { - g_cmdLine.bSetFullScreen = true; - } -#define CMD_FS_HEIGHT "-fs-height=" - else if (strncmp(lpCmdLine, CMD_FS_HEIGHT, sizeof(CMD_FS_HEIGHT)-1) == 0) - { - g_cmdLine.bSetFullScreen = true; // Implied - - LPSTR lpTmp = lpCmdLine + sizeof(CMD_FS_HEIGHT)-1; - bool bRes = false; - if (strcmp(lpTmp, "best") == 0) - { - bRes = GetBestDisplayResolutionForFullScreen(g_cmdLine.bestWidth, g_cmdLine.bestHeight); - } - else - { - UINT userSpecifiedHeight = atoi(lpTmp); - if (userSpecifiedHeight) - bRes = GetBestDisplayResolutionForFullScreen(g_cmdLine.bestWidth, g_cmdLine.bestHeight, userSpecifiedHeight); - else - LogFileOutput("Invalid cmd-line parameter for -fs-height=x switch\n"); - } - if (bRes) - LogFileOutput("Best resolution for -fs-height=x switch: Width=%d, Height=%d\n", g_cmdLine.bestWidth, g_cmdLine.bestHeight); - else - LogFileOutput("Failed to set parameter for -fs-height=x switch\n"); - } - else if (strcmp(lpCmdLine, "-no-di") == 0) - { - g_bDisableDirectInput = true; - } - else if (strcmp(lpCmdLine, "-m") == 0) - { - g_bDisableDirectSound = true; - } - else if (strcmp(lpCmdLine, "-no-mb") == 0) - { - g_bDisableDirectSoundMockingboard = true; - } - else if (strcmp(lpCmdLine, "-memclear") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_nMemoryClearType = atoi(lpCmdLine); - if (g_nMemoryClearType < 0) - g_nMemoryClearType = 0; - else - if (g_nMemoryClearType >= NUM_MIP) - g_nMemoryClearType = NUM_MIP - 1; - } -#ifdef RAMWORKS - else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.uRamWorksExPages = atoi(lpCmdLine); - if (g_cmdLine.uRamWorksExPages > kMaxExMemoryBanks) - g_cmdLine.uRamWorksExPages = kMaxExMemoryBanks; - else - if (g_cmdLine.uRamWorksExPages < 1) - g_cmdLine.uRamWorksExPages = 1; - } -#endif - else if (strcmp(lpCmdLine, "-s0") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (strcmp(lpCmdLine, "saturn") == 0 || strcmp(lpCmdLine, "saturn128") == 0) - g_cmdLine.uSaturnBanks = Saturn128K::kMaxSaturnBanks; - else if (strcmp(lpCmdLine, "saturn64") == 0) - g_cmdLine.uSaturnBanks = Saturn128K::kMaxSaturnBanks/2; - else if (strcmp(lpCmdLine, "languagecard") == 0 || strcmp(lpCmdLine, "lc") == 0) - g_cmdLine.bSlot0LanguageCard = true; - } - else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) // Stop resource leak if -f8rom is specified twice! - CloseHandle(g_hCustomRomF8); - - g_hCustomRomF8 = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) - g_bCustomRomF8Failed = true; - } - else if (strcmp(lpCmdLine, "-rom") == 0) // Use custom 16K at [$C000..$FFFF] or 12K ROM at [$D000..$FFFF] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (g_hCustomRom != INVALID_HANDLE_VALUE) // Stop resource leak if -rom is specified twice! - CloseHandle(g_hCustomRom); - - g_hCustomRom = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if ((g_hCustomRom == INVALID_HANDLE_VALUE) || ((GetFileSize(g_hCustomRom, NULL) != 0x4000) && (GetFileSize(g_hCustomRom, NULL) != 0x3000))) - g_bCustomRomFailed = true; - } - else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 2K (for II/II+). Use 4K,8K or 16K video ROM (for Enhanced //e) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (!ReadVideoRomFile(lpCmdLine)) - { - std::string msg = "Failed to load video rom (not found or not exactly 2/4/8/16KiB)\n"; - LogFileOutput("%s", msg.c_str()); - MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); - } - else - { - SetVideoRomRockerSwitch(true); // Use PAL char set - } - } - else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to - { - g_bDisplayPrintScreenFileName = true; - } - else if (strcmp(lpCmdLine, "-no-printscreen-key") == 0) // Don't try to capture PrintScreen key GH#469 - { - g_bCapturePrintScreenKey = false; - } - else if (strcmp(lpCmdLine, "-no-printscreen-dlg") == 0) // Turn off the PrintScreen warning message dialog (if PrintScreen key can't be grabbed) - { - g_bShowPrintScreenWarningDialog = false; - } - else if (strcmp(lpCmdLine, "-no-hook-system-key") == 0) // Don't hook the System keys (eg. Left-ALT+ESC/SPACE/TAB) GH#556 - { - g_bHookSystemKey = false; - } - else if (strcmp(lpCmdLine, "-hook-alt-tab") == 0) // GH#556 - { - g_bHookAltTab = true; - } - else if (strcmp(lpCmdLine, "-hook-altgr-control") == 0) // GH#556 - { - g_bHookAltGrControl = true; - } - else if (strcmp(lpCmdLine, "-altgr-sends-wmchar") == 0) // GH#625 - { - KeybSetAltGrSendsWM_CHAR(true); - } - else if (strcmp(lpCmdLine, "-no-hook-alt") == 0) // GH#583 - { - JoySetHookAltKeys(false); - } - else if (strcmp(lpCmdLine, "-left-alt-control-buttons") == 0) // GH#743 - { - JoySetButtonVirtualKey(0, VK_CONTROL); - JoySetButtonVirtualKey(1, VK_MENU); - } - else if (strcmp(lpCmdLine, "-right-alt-control-buttons") == 0) // GH#743 - { - JoySetButtonVirtualKey(0, VK_MENU | KF_EXTENDED); - JoySetButtonVirtualKey(1, VK_CONTROL | KF_EXTENDED); - } - else if (strcmp(lpCmdLine, "-swap-buttons") == 0) - { - g_cmdLine.bSwapButtons0and1 = true; - } - else if (strcmp(lpCmdLine, "-spkr-inc") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - const int nErrorInc = atoi(lpCmdLine); - SoundCore_SetErrorInc( nErrorInc ); - } - else if (strcmp(lpCmdLine, "-spkr-max") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - const int nErrorMax = atoi(lpCmdLine); - SoundCore_SetErrorMax( nErrorMax ); - } - else if (strcmp(lpCmdLine, "-use-real-printer") == 0) // Enable control in Advanced config to allow dumping to a real printer - { - g_bEnableDumpToRealPrinter = true; - } - else if (strcmp(lpCmdLine, "-speech") == 0) - { - g_bEnableSpeech = true; - } - else if (strcmp(lpCmdLine, "-multimon") == 0) - { - g_bMultiMon = true; - } - else if ((strcmp(lpCmdLine, "-dcd") == 0) || (strcmp(lpCmdLine, "-modem") == 0)) // GH#386 - { - if (GetCardMgr().IsSSCInstalled()) - GetCardMgr().GetSSC()->SupportDCD(true); - } - else if (strcmp(lpCmdLine, "-alt-enter=toggle-full-screen") == 0) // GH#556 - { - SetAltEnterToggleFullScreen(true); - } - else if (strcmp(lpCmdLine, "-alt-enter=open-apple-enter") == 0) // GH#556 - { - SetAltEnterToggleFullScreen(false); - } - else if (strcmp(lpCmdLine, "-video-mode=idealized") == 0) // GH#616 - { - g_cmdLine.newVideoType = VT_COLOR_IDEALIZED; - } - else if (strcmp(lpCmdLine, "-video-mode=rgb-videocard") == 0) - { - g_cmdLine.newVideoType = VT_COLOR_VIDEOCARD_RGB; - } - else if (strcmp(lpCmdLine, "-video-mode=composite-monitor") == 0) // GH#763 - { - g_cmdLine.newVideoType = VT_COLOR_MONITOR_NTSC; - } - else if (strcmp(lpCmdLine, "-video-style=vertical-blend") == 0) // GH#616 - { - g_cmdLine.newVideoStyleEnableMask = VS_COLOR_VERTICAL_BLEND; - } - else if (strcmp(lpCmdLine, "-video-style=no-vertical-blend") == 0) // GH#616 - { - g_cmdLine.newVideoStyleDisableMask = VS_COLOR_VERTICAL_BLEND; - } - else if (strcmp(lpCmdLine, "-rgb-card-invert-bit7") == 0) // GH#633 - { - RGB_SetInvertBit7(true); - } - else if (strcmp(lpCmdLine, "-screenshot-and-exit") == 0) // GH#616: For testing - Use in combination with -load-state - { - g_cmdLine.szScreenshotFilename = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - } - else if (strcmp(lpCmdLine, "-clock-multiplier") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.clockMultiplier = atof(lpCmdLine); - } - else if (strcmp(lpCmdLine, "-model") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (strcmp(lpCmdLine, "apple2") == 0) - g_cmdLine.model = A2TYPE_APPLE2; - else if (strcmp(lpCmdLine, "apple2p") == 0) - g_cmdLine.model = A2TYPE_APPLE2PLUS; - else if (strcmp(lpCmdLine, "apple2jp") == 0) - g_cmdLine.model = A2TYPE_APPLE2JPLUS; - else if (strcmp(lpCmdLine, "apple2e") == 0) - g_cmdLine.model = A2TYPE_APPLE2E; - else if (strcmp(lpCmdLine, "apple2ee") == 0) - g_cmdLine.model = A2TYPE_APPLE2EENHANCED; - else - LogFileOutput("-model: unsupported type: %s\n", lpCmdLine); - } - else if (_stricmp(lpCmdLine, "-50hz") == 0) // (case-insensitive) - { - g_cmdLine.newVideoRefreshRate = VR_50HZ; - } - else if (_stricmp(lpCmdLine, "-60hz") == 0) // (case-insensitive) - { - g_cmdLine.newVideoRefreshRate = VR_60HZ; - } - else if (strcmp(lpCmdLine, "-rgb-card-type") == 0) - { - // RGB video card valid types are: "apple", "sl7", "eve", "feline" - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - - if (strcmp(lpCmdLine, "apple") == 0) // Just an alias for SL7 - g_cmdLine.rgbCard = RGB_Videocard_e::Apple; - else if (strcmp(lpCmdLine, "sl7") == 0) - g_cmdLine.rgbCard = RGB_Videocard_e::Video7_SL7; - else if (strcmp(lpCmdLine, "eve") == 0) - g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_EVE; - else if (strcmp(lpCmdLine, "feline") == 0) - g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_Feline; - else - LogFileOutput("-rgb-card-type: unsupported type: %s\n", lpCmdLine); - } - else if (strcmp(lpCmdLine, "-rgb-card-foreground") == 0) - { - // Default hardware-defined Text foreground color, for Video-7's RGB-SL7 card only - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.rgbCardForegroundColor = atoi(lpCmdLine); - } - else if (strcmp(lpCmdLine, "-rgb-card-background") == 0) - { - // Default hardware-defined Text background color, for Video-7's RGB-SL7 card only - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.rgbCardBackgroundColor = atoi(lpCmdLine); - } - else if (strcmp(lpCmdLine, "-power-on") == 0) - { - g_cmdLine.bBoot = true; - } - else if (strcmp(lpCmdLine, "-current-dir") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_cmdLine.strCurrentDir = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-no-nsc") == 0) - { - g_cmdLine.bRemoveNoSlotClock = true; - } - else // unsupported - { - LogFileOutput("Unsupported arg: %s\n", lpCmdLine); - strUnsupported += lpCmdLine; - strUnsupported += "\n"; - } - - lpCmdLine = lpNextArg; - } - - LogFileOutput("CmdLine: %s\n", strCmdLine.c_str()); - - bool ok = true; - - if (!strUnsupported.empty()) - { - std::string msg("Unsupported commands:\n\n"); - msg += strUnsupported; - msg += "\n"; - msg += "Continue running AppleWin?"; - int res = MessageBox(GetDesktopWindow(), // NB. g_hFrameWindow is not yet valid - msg.c_str(), - "AppleWin Command Line", - MB_ICONSTOP | MB_SETFOREGROUND | MB_YESNO); - ok = (res != IDNO); - } - - return ok; -} - -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, TEXT("\\"), (LPVOID*) &pFixedFileInfo, (PUINT) &pFixedFileInfoLen); - - // Construct version string from fixed file info block - - unsigned long major = g_AppleWinVersion[0] = pFixedFileInfo->dwFileVersionMS >> 16; - unsigned long minor = g_AppleWinVersion[1] = pFixedFileInfo->dwFileVersionMS & 0xffff; - unsigned long fix = g_AppleWinVersion[2] = pFixedFileInfo->dwFileVersionLS >> 16; - unsigned long fix_minor = g_AppleWinVersion[3] = pFixedFileInfo->dwFileVersionLS & 0xffff; - StringCbPrintf(VERSIONSTRING, VERSIONSTRING_SIZE, "%d.%d.%d.%d", major, minor, fix, fix_minor); - } - - delete [] pVerInfoBlock; - } - - LogFileOutput("AppleWin version: %s\n", VERSIONSTRING); -} - -// DO ONE-TIME INITIALIZATION -static void OneTimeInitialization(HINSTANCE passinstance) -{ -#if 0 -#ifdef RIFF_SPKR - RiffInitWriteFile("Spkr.wav", SPKR_SAMPLE_RATE, 1); -#endif -#ifdef RIFF_MB - RiffInitWriteFile("Mockingboard.wav", 44100, 2); -#endif -#endif - - // Initialize COM - so we can use CoCreateInstance - // . NB. DSInit() & DIMouse::DirectInputInit are done when g_hFrameWindow is created (WM_CREATE) - 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 -#if 0 - DDInit(); // For WaitForVerticalBlank() -#endif - - g_hInstance = passinstance; - GdiSetBatchLimit(512); - LogFileOutput("Init: GdiSetBatchLimit()\n"); - - GetProgramDirectory(); - LogFileOutput("Init: GetProgramDirectory()\n"); - - if (g_bRegisterFileTypes) - { - RegisterExtensions(); - LogFileOutput("Init: RegisterExtensions()\n"); - } - - FrameRegisterClass(); - LogFileOutput("Init: FrameRegisterClass()\n"); - - ImageInitialize(); - LogFileOutput("Init: ImageInitialize()\n"); -} - -// DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART -static void RepeatInitialization(void) -{ - ResetToLogoMode(); - - // NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video() - const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion - - LoadConfiguration(); - LogFileOutput("Main: LoadConfiguration()\n"); - - if (g_cmdLine.model != A2TYPE_MAX) - SetApple2Type(g_cmdLine.model); - - RGB_SetVideocard(g_cmdLine.rgbCard, g_cmdLine.rgbCardForegroundColor, g_cmdLine.rgbCardBackgroundColor); - - if (g_cmdLine.newVideoType >= 0) - { - SetVideoType( (VideoType_e)g_cmdLine.newVideoType ); - g_cmdLine.newVideoType = -1; // Don't reapply after a restart - } - SetVideoStyle( (VideoStyle_e) ((GetVideoStyle() | g_cmdLine.newVideoStyleEnableMask) & ~g_cmdLine.newVideoStyleDisableMask) ); - - if (g_cmdLine.newVideoRefreshRate != VR_NONE) - { - 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 -#ifdef RAMWORKS - if (g_cmdLine.uRamWorksExPages) - { - SetRamWorksMemorySize(g_cmdLine.uRamWorksExPages); - SetExpansionMemType(CT_RamWorksIII); - g_cmdLine.uRamWorksExPages = 0; // Don't reapply after a restart - } -#endif - if (g_cmdLine.uSaturnBanks) - { - SetSaturnMemorySize(g_cmdLine.uSaturnBanks); // Set number of banks before constructing Saturn card - SetExpansionMemType(CT_Saturn128K); - g_cmdLine.uSaturnBanks = 0; // Don't reapply after a restart - } - - if (g_cmdLine.bSlot0LanguageCard) - { - SetExpansionMemType(CT_LanguageCard); - g_cmdLine.bSlot0LanguageCard = false; // Don't reapply after a restart - } - - if (g_cmdLine.bSwapButtons0and1) - { - sg_PropertySheet.SetButtonsSwapState(true); - // Reapply after a restart - TODO: grey-out the Config UI for "Swap 0/1" when this cmd line is passed in - } - - DebugInitialize(); - LogFileOutput("Main: DebugInitialize()\n"); - - JoyInitialize(); - LogFileOutput("Main: JoyInitialize()\n"); - - WinVideoInitialize(); // g_pFramebufferinfo been created now - LogFileOutput("Main: VideoInitialize()\n"); - - LogFileOutput("Main: FrameCreateWindow() - pre\n"); - FrameCreateWindow(); // g_hFrameWindow is now valid - LogFileOutput("Main: FrameCreateWindow() - post\n"); - - // Init palette color - VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType()); - - // Allow the 4 hardcoded slots to be configurated as empty - // NB. this state is not persisted to the Registry/conf.ini (just as '-s7 empty' isn't) - // TODO: support bSlotEmpty[] for slots: 0,4,5 - if (g_cmdLine.bSlotEmpty[SLOT1]) - GetCardMgr().Remove(SLOT1); - if (g_cmdLine.bSlotEmpty[SLOT2]) - GetCardMgr().Remove(SLOT2); - if (g_cmdLine.bSlotEmpty[SLOT3]) - GetCardMgr().Remove(SLOT3); - if (g_cmdLine.bSlotEmpty[SLOT6]) - GetCardMgr().Remove(SLOT6); - - if (g_cmdLine.slotInsert[SLOT5] != CT_Empty) - { - if (GetCardMgr().QuerySlot(SLOT4) == CT_MockingboardC && g_cmdLine.slotInsert[SLOT5] != CT_MockingboardC) // Currently MB occupies slot4+5 when enabled - { - GetCardMgr().Remove(SLOT4); - GetCardMgr().Remove(SLOT5); - } - - GetCardMgr().Insert(SLOT5, g_cmdLine.slotInsert[SLOT5]); - } - - // Pre: may need g_hFrameWindow for MessageBox errors - // Post: may enable HDD, required for MemInitialize()->MemInitializeIO() - { - bool temp = false; - InsertFloppyDisks(SLOT5, g_cmdLine.szImageName_drive[SLOT5], temp); - //g_cmdLine.szImageName_drive[SLOT5][DRIVE_1] = g_cmdLine.szImageName_drive[SLOT5][DRIVE_2] = NULL; // *Do* insert on a restart (since no way they could have changed) - - InsertFloppyDisks(SLOT6, g_cmdLine.szImageName_drive[SLOT6], g_cmdLine.bBoot); - g_cmdLine.szImageName_drive[SLOT6][DRIVE_1] = g_cmdLine.szImageName_drive[SLOT6][DRIVE_2] = NULL; // Don't insert on a restart - - InsertHardDisks(g_cmdLine.szImageName_harddisk, g_cmdLine.bBoot); - g_cmdLine.szImageName_harddisk[HARDDISK_1] = g_cmdLine.szImageName_harddisk[HARDDISK_2] = NULL; // Don't insert on a restart - - if (g_cmdLine.bSlotEmpty[7]) - { - HD_SetEnabled(false); // Disable HDD controller, but don't persist this to Registry/conf.ini (consistent with other '-sn empty' cmds) - 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(); - - 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(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license - } - - if (g_bCapturePrintScreenKey) - { - RegisterHotKeys(); // needs valid g_hFrameWindow - LogFileOutput("Main: RegisterHotKeys()\n"); - } - - if (g_bHookSystemKey) - { - if (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 call Disk2Card's Reset(): - GetCardMgr().GetDisk2CardMgr().Reset(true); // Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor - LogFileOutput("Main: DiskReset()\n"); - HD_Reset(); // GH#515 - LogFileOutput("Main: HDDReset()\n"); - - if (!g_bSysClkOK) - { - MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("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()); - MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); - g_cmdLine.bShutdown = true; - } - - tfe_init(); - LogFileOutput("Main: tfe_init()\n"); - - if (g_cmdLine.szSnapshotName) - { - std::string strPathname(g_cmdLine.szSnapshotName); - int nIdx = strPathname.find_last_of('\\'); - 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_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) - { - Video_RedrawAndTakeScreenShot(g_cmdLine.szScreenshotFilename); - g_cmdLine.bShutdown = true; - } - - if (g_cmdLine.bShutdown) - { - PostMessage(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.bSetFullScreen) - { - if (g_cmdLine.bestWidth && g_cmdLine.bestHeight) - { - DEVMODE devMode; - memset(&devMode, 0, sizeof(devMode)); - devMode.dmSize = sizeof(devMode); - devMode.dmPelsWidth = g_cmdLine.bestWidth; - devMode.dmPelsHeight = g_cmdLine.bestHeight; - devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - - DWORD dwFlags = 0; - LONG res = ChangeDisplaySettings(&devMode, dwFlags); - if (res == 0) - g_cmdLine.bChangedDisplayResolution = true; - } - - PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); - g_cmdLine.bSetFullScreen = false; - } - - if (g_cmdLine.bBoot) - { - PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); - g_cmdLine.bBoot = false; - } - } -} - -static void Shutdown(void) -{ - if (g_cmdLine.bChangedDisplayResolution) - ChangeDisplaySettings(NULL, 0); // restore default - - // Release COM - DDUninit(); - SysClk_UninitTimer(); - LogFileOutput("Exit: SysClk_UninitTimer()\n"); - - CoUninitialize(); - LogFileOutput("Exit: CoUninitialize()\n"); - - tfe_shutdown(); - LogFileOutput("Exit: tfe_shutdown()\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) - UnplugHardDiskControllerCard(); -} diff --git a/source/CPU.cpp b/source/CPU.cpp index 9a3e3368..a6b4f6e1 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -87,7 +87,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "CPU.h" -#include "AppleWin.h" +#include "Core.h" #include "CardManager.h" #include "Memory.h" #include "Mockingboard.h" diff --git a/source/CardManager.cpp b/source/CardManager.cpp index 86e142ef..d71e31b1 100644 --- a/source/CardManager.cpp +++ b/source/CardManager.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "CardManager.h" -#include "AppleWin.h" +#include "Core.h" #include "Disk.h" #include "MouseInterface.h" diff --git a/source/CmdLine.cpp b/source/CmdLine.cpp new file mode 100644 index 00000000..f6ffe967 --- /dev/null +++ b/source/CmdLine.cpp @@ -0,0 +1,527 @@ +/* +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 "CmdLine.h" +#include "Log.h" +#include "Core.h" +#include "Memory.h" +#include "LanguageCard.h" +#include "Keyboard.h" +#include "Joystick.h" +#include "SoundCore.h" +#include "ParallelPrinter.h" +#include "CardManager.h" +#include "SerialComms.h" +#include "Windows/WinFrame.h" + +CmdLine g_cmdLine; +std::string g_sConfigFile; // INI file to use instead of Registry + +bool g_bCapturePrintScreenKey = true; +bool g_bRegisterFileTypes = true; +bool g_bHookSystemKey = true; +bool g_bHookAltTab = false; +bool g_bHookAltGrControl = false; + +static LPSTR GetCurrArg(LPSTR lpCmdLine) +{ + if(*lpCmdLine == '\"') + lpCmdLine++; + + return lpCmdLine; +} + +static LPSTR GetNextArg(LPSTR lpCmdLine) +{ + int bInQuotes = 0; + + while(*lpCmdLine) + { + if(*lpCmdLine == '\"') + { + bInQuotes ^= 1; + if(!bInQuotes) + { + *lpCmdLine++ = 0x00; // Assume end-quote is end of this arg + continue; + } + } + + if((*lpCmdLine == ' ') && !bInQuotes) + { + *lpCmdLine++ = 0x00; + break; + } + + lpCmdLine++; + } + + return lpCmdLine; +} + +//--------------------------------------------------------------------------- + +bool ProcessCmdLine(LPSTR lpCmdLine) +{ + const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput + std::string strUnsupported; + + // If 1st param looks like an abs pathname then assume that an associated filetype has been double-clicked + // NB. Handled by WM_DDE_INITIATE & WM_DDE_EXECUTE msgs + if ((lpCmdLine[0] >= '\"' && lpCmdLine[1] >= 'A' && lpCmdLine[1] <= 'Z' && lpCmdLine[2] == ':') // always in quotes + || strncmp("\\\\?\\", lpCmdLine, 4) == 0) + return true; + + while (*lpCmdLine) + { + LPSTR lpNextArg = GetNextArg(lpCmdLine); + + if (((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL)) + { + LogInit(); + } + else if (strcmp(lpCmdLine, "-noreg") == 0) + { + g_bRegisterFileTypes = false; + } + else if (strcmp(lpCmdLine, "-conf") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + char buf[MAX_PATH]; + DWORD res = GetFullPathName(lpCmdLine, MAX_PATH, buf, NULL); + if (res == 0) + LogFileOutput("Failed to open configuration file: %s\n", lpCmdLine); + else + g_sConfigFile = buf; + } + else if (strcmp(lpCmdLine, "-d1") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szImageName_drive[SLOT6][DRIVE_1] = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-d2") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szImageName_drive[SLOT6][DRIVE_2] = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-h1") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szImageName_harddisk[HARDDISK_1] = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-h2") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szImageName_harddisk[HARDDISK_2] = lpCmdLine; + } + else if (lpCmdLine[0] == '-' && lpCmdLine[1] == 's' && lpCmdLine[2] >= '1' && lpCmdLine[2] <= '7') + { + const UINT slot = lpCmdLine[2] - '0'; + + if (lpCmdLine[3] == 0) // -s[1..7] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + if (strcmp(lpCmdLine, "empty") == 0) + g_cmdLine.bSlotEmpty[slot] = true; + if (strcmp(lpCmdLine, "diskii") == 0) + g_cmdLine.slotInsert[slot] = CT_Disk2; + } + else if (lpCmdLine[3] == 'd' && (lpCmdLine[4] == '1' || lpCmdLine[4] == '2')) // -s[1..7]d[1|2] + { + const UINT drive = lpCmdLine[4] == '1' ? DRIVE_1 : DRIVE_2; + + if (slot != 5 && slot != 6) + { + LogFileOutput("Unsupported arg: %s\n", lpCmdLine); + } + else + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szImageName_drive[slot][drive] = lpCmdLine; + } + } + else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0) + { + g_cmdLine.bSlot7EmptyOnExit = true; + } + else + { + LogFileOutput("Unsupported arg: %s\n", lpCmdLine); + } + } + else if (strcmp(lpCmdLine, "-load-state") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.szSnapshotName = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-f") == 0) + { + g_cmdLine.bSetFullScreen = true; + } +#define CMD_FS_HEIGHT "-fs-height=" + else if (strncmp(lpCmdLine, CMD_FS_HEIGHT, sizeof(CMD_FS_HEIGHT)-1) == 0) + { + g_cmdLine.bSetFullScreen = true; // Implied + + LPSTR lpTmp = lpCmdLine + sizeof(CMD_FS_HEIGHT)-1; + bool bRes = false; + if (strcmp(lpTmp, "best") == 0) + { + bRes = GetBestDisplayResolutionForFullScreen(g_cmdLine.bestWidth, g_cmdLine.bestHeight); + } + else + { + UINT userSpecifiedHeight = atoi(lpTmp); + if (userSpecifiedHeight) + bRes = GetBestDisplayResolutionForFullScreen(g_cmdLine.bestWidth, g_cmdLine.bestHeight, userSpecifiedHeight); + else + LogFileOutput("Invalid cmd-line parameter for -fs-height=x switch\n"); + } + if (bRes) + LogFileOutput("Best resolution for -fs-height=x switch: Width=%d, Height=%d\n", g_cmdLine.bestWidth, g_cmdLine.bestHeight); + else + LogFileOutput("Failed to set parameter for -fs-height=x switch\n"); + } + else if (strcmp(lpCmdLine, "-no-di") == 0) + { + g_bDisableDirectInput = true; + } + else if (strcmp(lpCmdLine, "-m") == 0) + { + g_bDisableDirectSound = true; + } + else if (strcmp(lpCmdLine, "-no-mb") == 0) + { + g_bDisableDirectSoundMockingboard = true; + } + else if (strcmp(lpCmdLine, "-memclear") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_nMemoryClearType = atoi(lpCmdLine); + if (g_nMemoryClearType < 0) + g_nMemoryClearType = 0; + else + if (g_nMemoryClearType >= NUM_MIP) + g_nMemoryClearType = NUM_MIP - 1; + } +#ifdef RAMWORKS + else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.uRamWorksExPages = atoi(lpCmdLine); + if (g_cmdLine.uRamWorksExPages > kMaxExMemoryBanks) + g_cmdLine.uRamWorksExPages = kMaxExMemoryBanks; + else + if (g_cmdLine.uRamWorksExPages < 1) + g_cmdLine.uRamWorksExPages = 1; + } +#endif + else if (strcmp(lpCmdLine, "-s0") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (strcmp(lpCmdLine, "saturn") == 0 || strcmp(lpCmdLine, "saturn128") == 0) + g_cmdLine.uSaturnBanks = Saturn128K::kMaxSaturnBanks; + else if (strcmp(lpCmdLine, "saturn64") == 0) + g_cmdLine.uSaturnBanks = Saturn128K::kMaxSaturnBanks/2; + else if (strcmp(lpCmdLine, "languagecard") == 0 || strcmp(lpCmdLine, "lc") == 0) + g_cmdLine.bSlot0LanguageCard = true; + } + else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) // Stop resource leak if -f8rom is specified twice! + CloseHandle(g_hCustomRomF8); + + g_hCustomRomF8 = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) + g_bCustomRomF8Failed = true; + } + else if (strcmp(lpCmdLine, "-rom") == 0) // Use custom 16K at [$C000..$FFFF] or 12K ROM at [$D000..$FFFF] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (g_hCustomRom != INVALID_HANDLE_VALUE) // Stop resource leak if -rom is specified twice! + CloseHandle(g_hCustomRom); + + g_hCustomRom = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if ((g_hCustomRom == INVALID_HANDLE_VALUE) || ((GetFileSize(g_hCustomRom, NULL) != 0x4000) && (GetFileSize(g_hCustomRom, NULL) != 0x3000))) + g_bCustomRomFailed = true; + } + else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 2K (for II/II+). Use 4K,8K or 16K video ROM (for Enhanced //e) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (!ReadVideoRomFile(lpCmdLine)) + { + std::string msg = "Failed to load video rom (not found or not exactly 2/4/8/16KiB)\n"; + LogFileOutput("%s", msg.c_str()); + MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); + } + else + { + SetVideoRomRockerSwitch(true); // Use PAL char set + } + } + else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to + { + g_bDisplayPrintScreenFileName = true; + } + else if (strcmp(lpCmdLine, "-no-printscreen-key") == 0) // Don't try to capture PrintScreen key GH#469 + { + g_bCapturePrintScreenKey = false; + } + else if (strcmp(lpCmdLine, "-no-printscreen-dlg") == 0) // Turn off the PrintScreen warning message dialog (if PrintScreen key can't be grabbed) + { + g_bShowPrintScreenWarningDialog = false; + } + else if (strcmp(lpCmdLine, "-no-hook-system-key") == 0) // Don't hook the System keys (eg. Left-ALT+ESC/SPACE/TAB) GH#556 + { + g_bHookSystemKey = false; + } + else if (strcmp(lpCmdLine, "-hook-alt-tab") == 0) // GH#556 + { + g_bHookAltTab = true; + } + else if (strcmp(lpCmdLine, "-hook-altgr-control") == 0) // GH#556 + { + g_bHookAltGrControl = true; + } + else if (strcmp(lpCmdLine, "-altgr-sends-wmchar") == 0) // GH#625 + { + KeybSetAltGrSendsWM_CHAR(true); + } + else if (strcmp(lpCmdLine, "-no-hook-alt") == 0) // GH#583 + { + JoySetHookAltKeys(false); + } + else if (strcmp(lpCmdLine, "-left-alt-control-buttons") == 0) // GH#743 + { + JoySetButtonVirtualKey(0, VK_CONTROL); + JoySetButtonVirtualKey(1, VK_MENU); + } + else if (strcmp(lpCmdLine, "-right-alt-control-buttons") == 0) // GH#743 + { + JoySetButtonVirtualKey(0, VK_MENU | KF_EXTENDED); + JoySetButtonVirtualKey(1, VK_CONTROL | KF_EXTENDED); + } + else if (strcmp(lpCmdLine, "-swap-buttons") == 0) + { + g_cmdLine.bSwapButtons0and1 = true; + } + else if (strcmp(lpCmdLine, "-spkr-inc") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + const int nErrorInc = atoi(lpCmdLine); + SoundCore_SetErrorInc( nErrorInc ); + } + else if (strcmp(lpCmdLine, "-spkr-max") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + const int nErrorMax = atoi(lpCmdLine); + SoundCore_SetErrorMax( nErrorMax ); + } + else if (strcmp(lpCmdLine, "-use-real-printer") == 0) // Enable control in Advanced config to allow dumping to a real printer + { + g_bEnableDumpToRealPrinter = true; + } + else if (strcmp(lpCmdLine, "-speech") == 0) + { + g_bEnableSpeech = true; + } + else if (strcmp(lpCmdLine, "-multimon") == 0) + { + g_bMultiMon = true; + } + else if ((strcmp(lpCmdLine, "-dcd") == 0) || (strcmp(lpCmdLine, "-modem") == 0)) // GH#386 + { + if (GetCardMgr().IsSSCInstalled()) + GetCardMgr().GetSSC()->SupportDCD(true); + } + else if (strcmp(lpCmdLine, "-alt-enter=toggle-full-screen") == 0) // GH#556 + { + SetAltEnterToggleFullScreen(true); + } + else if (strcmp(lpCmdLine, "-alt-enter=open-apple-enter") == 0) // GH#556 + { + SetAltEnterToggleFullScreen(false); + } + else if (strcmp(lpCmdLine, "-video-mode=idealized") == 0) // GH#616 + { + g_cmdLine.newVideoType = VT_COLOR_IDEALIZED; + } + else if (strcmp(lpCmdLine, "-video-mode=rgb-videocard") == 0) + { + g_cmdLine.newVideoType = VT_COLOR_VIDEOCARD_RGB; + } + else if (strcmp(lpCmdLine, "-video-mode=composite-monitor") == 0) // GH#763 + { + g_cmdLine.newVideoType = VT_COLOR_MONITOR_NTSC; + } + else if (strcmp(lpCmdLine, "-video-style=vertical-blend") == 0) // GH#616 + { + g_cmdLine.newVideoStyleEnableMask = VS_COLOR_VERTICAL_BLEND; + } + else if (strcmp(lpCmdLine, "-video-style=no-vertical-blend") == 0) // GH#616 + { + g_cmdLine.newVideoStyleDisableMask = VS_COLOR_VERTICAL_BLEND; + } + else if (strcmp(lpCmdLine, "-rgb-card-invert-bit7") == 0) // GH#633 + { + RGB_SetInvertBit7(true); + } + else if (strcmp(lpCmdLine, "-screenshot-and-exit") == 0) // GH#616: For testing - Use in combination with -load-state + { + g_cmdLine.szScreenshotFilename = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + } + else if (strcmp(lpCmdLine, "-clock-multiplier") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.clockMultiplier = atof(lpCmdLine); + } + else if (strcmp(lpCmdLine, "-model") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (strcmp(lpCmdLine, "apple2") == 0) + g_cmdLine.model = A2TYPE_APPLE2; + else if (strcmp(lpCmdLine, "apple2p") == 0) + g_cmdLine.model = A2TYPE_APPLE2PLUS; + else if (strcmp(lpCmdLine, "apple2jp") == 0) + g_cmdLine.model = A2TYPE_APPLE2JPLUS; + else if (strcmp(lpCmdLine, "apple2e") == 0) + g_cmdLine.model = A2TYPE_APPLE2E; + else if (strcmp(lpCmdLine, "apple2ee") == 0) + g_cmdLine.model = A2TYPE_APPLE2EENHANCED; + else + LogFileOutput("-model: unsupported type: %s\n", lpCmdLine); + } + else if (_stricmp(lpCmdLine, "-50hz") == 0) // (case-insensitive) + { + g_cmdLine.newVideoRefreshRate = VR_50HZ; + } + else if (_stricmp(lpCmdLine, "-60hz") == 0) // (case-insensitive) + { + g_cmdLine.newVideoRefreshRate = VR_60HZ; + } + else if (strcmp(lpCmdLine, "-rgb-card-type") == 0) + { + // RGB video card valid types are: "apple", "sl7", "eve", "feline" + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (strcmp(lpCmdLine, "apple") == 0) // Just an alias for SL7 + g_cmdLine.rgbCard = RGB_Videocard_e::Apple; + else if (strcmp(lpCmdLine, "sl7") == 0) + g_cmdLine.rgbCard = RGB_Videocard_e::Video7_SL7; + else if (strcmp(lpCmdLine, "eve") == 0) + g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_EVE; + else if (strcmp(lpCmdLine, "feline") == 0) + g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_Feline; + else + LogFileOutput("-rgb-card-type: unsupported type: %s\n", lpCmdLine); + } + else if (strcmp(lpCmdLine, "-rgb-card-foreground") == 0) + { + // Default hardware-defined Text foreground color, for Video-7's RGB-SL7 card only + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.rgbCardForegroundColor = atoi(lpCmdLine); + } + else if (strcmp(lpCmdLine, "-rgb-card-background") == 0) + { + // Default hardware-defined Text background color, for Video-7's RGB-SL7 card only + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.rgbCardBackgroundColor = atoi(lpCmdLine); + } + else if (strcmp(lpCmdLine, "-power-on") == 0) + { + g_cmdLine.bBoot = true; + } + else if (strcmp(lpCmdLine, "-current-dir") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.strCurrentDir = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-no-nsc") == 0) + { + g_cmdLine.bRemoveNoSlotClock = true; + } + else // unsupported + { + LogFileOutput("Unsupported arg: %s\n", lpCmdLine); + strUnsupported += lpCmdLine; + strUnsupported += "\n"; + } + + lpCmdLine = lpNextArg; + } + + LogFileOutput("CmdLine: %s\n", strCmdLine.c_str()); + + bool ok = true; + + if (!strUnsupported.empty()) + { + std::string msg("Unsupported commands:\n\n"); + msg += strUnsupported; + msg += "\n"; + msg += "Continue running AppleWin?"; + int res = MessageBox(GetDesktopWindow(), // NB. g_hFrameWindow is not yet valid + msg.c_str(), + "AppleWin Command Line", + MB_ICONSTOP | MB_SETFOREGROUND | MB_YESNO); + ok = (res != IDNO); + } + + return ok; +} diff --git a/source/CmdLine.h b/source/CmdLine.h new file mode 100644 index 00000000..bdbd64de --- /dev/null +++ b/source/CmdLine.h @@ -0,0 +1,88 @@ +#pragma once + +#include "RgbMonitor.h" +#include "Harddisk.h" +#include "Disk.h" +#include "Video.h" +#include "Common.h" +#include "Card.h" + + +struct CmdLine +{ + CmdLine() + { + bShutdown = false; + bSetFullScreen = false; + bBoot = false; + bChangedDisplayResolution = false; + bSlot0LanguageCard = false; + bSlot7EmptyOnExit = false; + bSwapButtons0and1 = false; + bRemoveNoSlotClock = false; + bestWidth = 0; + bestHeight = 0; + szImageName_harddisk[HARDDISK_1] = NULL; + szImageName_harddisk[HARDDISK_2] = NULL; + szSnapshotName = NULL; + szScreenshotFilename = NULL; + uRamWorksExPages = 0; + uSaturnBanks = 0; + newVideoType = -1; + newVideoStyleEnableMask = 0; + newVideoStyleDisableMask = 0; + newVideoRefreshRate = VR_NONE; + clockMultiplier = 0.0; // 0 => not set from cmd-line + model = A2TYPE_MAX; + rgbCard = RGB_Videocard_e::Apple; + rgbCardForegroundColor = 15; + rgbCardBackgroundColor = 0; + + for (UINT i = 0; i < NUM_SLOTS; i++) + { + bSlotEmpty[i] = false; + slotInsert[i] = CT_Empty; + szImageName_drive[i][DRIVE_1] = NULL; + szImageName_drive[i][DRIVE_2] = NULL; + } + } + + bool bShutdown; + bool bSetFullScreen; + bool bBoot; + bool bChangedDisplayResolution; + bool bSlot0LanguageCard; + bool bSlotEmpty[NUM_SLOTS]; + bool bSlot7EmptyOnExit; + bool bSwapButtons0and1; + bool bRemoveNoSlotClock; + SS_CARDTYPE slotInsert[NUM_SLOTS]; + UINT bestWidth; + UINT bestHeight; + LPSTR szImageName_drive[NUM_SLOTS][NUM_DRIVES]; + LPSTR szImageName_harddisk[NUM_HARDDISKS]; + LPSTR szSnapshotName; + LPSTR szScreenshotFilename; + UINT uRamWorksExPages; + UINT uSaturnBanks; + int newVideoType; + int newVideoStyleEnableMask; + int newVideoStyleDisableMask; + VideoRefreshRate_e newVideoRefreshRate; + double clockMultiplier; + eApple2Type model; + RGB_Videocard_e rgbCard; + int rgbCardForegroundColor; + int rgbCardBackgroundColor; + std::string strCurrentDir; +}; + +bool ProcessCmdLine(LPSTR lpCmdLine); + +extern std::string g_sConfigFile; // INI file to use instead of Registry +extern bool g_bCapturePrintScreenKey; +extern bool g_bRegisterFileTypes; +extern bool g_bHookSystemKey; +extern bool g_bHookAltTab; +extern bool g_bHookAltGrControl; +extern CmdLine g_cmdLine; diff --git a/source/Configuration/About.cpp b/source/Configuration/About.cpp index 54456946..5bb57219 100644 --- a/source/Configuration/About.cpp +++ b/source/Configuration/About.cpp @@ -24,7 +24,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "About.h" -#include "../AppleWin.h" +#include "../Core.h" +#include "../Windows/AppleWin.h" #include "../Windows/WinFrame.h" #include "../resource/resource.h" diff --git a/source/Configuration/Config.h b/source/Configuration/Config.h index cf7dd085..0369ed48 100644 --- a/source/Configuration/Config.h +++ b/source/Configuration/Config.h @@ -1,6 +1,6 @@ #pragma once -#include "../AppleWin.h" +#include "../Core.h" #include "../CardManager.h" #include "../CPU.h" #include "../DiskImage.h" // Disk_Status_e diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index dabc68ff..37c27cd8 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "PageConfig.h" #include "PropertySheetHelper.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" #include "../Windows/WinFrame.h" #include "../Registry.h" #include "../SerialComms.h" diff --git a/source/Configuration/PageDisk.cpp b/source/Configuration/PageDisk.cpp index ac504d63..98ce4370 100644 --- a/source/Configuration/PageDisk.cpp +++ b/source/Configuration/PageDisk.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "PageDisk.h" #include "PropertySheetHelper.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" #include "../CardManager.h" #include "../Disk.h" // Drive_e, Disk_Status_e #include "../Windows/WinFrame.h" diff --git a/source/Configuration/PropertySheet.cpp b/source/Configuration/PropertySheet.cpp index f7cb3605..e9278206 100644 --- a/source/Configuration/PropertySheet.cpp +++ b/source/Configuration/PropertySheet.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "PropertySheet.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" #include "../Windows/WinFrame.h" #include "../resource/resource.h" diff --git a/source/Configuration/PropertySheetHelper.cpp b/source/Configuration/PropertySheetHelper.cpp index 77111765..97bb0fa7 100644 --- a/source/Configuration/PropertySheetHelper.cpp +++ b/source/Configuration/PropertySheetHelper.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "PropertySheetHelper.h" #include "IPropertySheet.h" -#include "../AppleWin.h" // g_nAppMode, g_uScrollLockToggle, sg_PropertySheet +#include "../Windows/AppleWin.h" // g_nAppMode, g_uScrollLockToggle, sg_PropertySheet #include "../CardManager.h" #include "../Disk.h" #include "../Windows/WinFrame.h" diff --git a/source/Core.cpp b/source/Core.cpp new file mode 100644 index 00000000..ea2ef7da --- /dev/null +++ b/source/Core.cpp @@ -0,0 +1,300 @@ +/* +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 "Core.h" +#include "CardManager.h" +#include "CPU.h" +#include "Video.h" +#include "Log.h" +#include "Memory.h" +#include "Mockingboard.h" +#include "Speaker.h" +#include "Registry.h" +#include "SynchronousEventManager.h" +#include "Configuration/PropertySheet.h" + +#ifdef USE_SPEECH_API +#include "Speech.h" +#endif + +static const UINT VERSIONSTRING_SIZE = 16; +static UINT16 g_OldAppleWinVersion[4] = {0}; +UINT16 g_AppleWinVersion[4] = { 0 }; +TCHAR VERSIONSTRING[VERSIONSTRING_SIZE] = "xx.yy.zz.ww"; + +std::string g_pAppTitle; + +eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; + +bool g_bFullSpeed = false; + +//================================================= + +AppMode_e g_nAppMode = MODE_LOGO; + +std::string g_sStartDir; // NB. AppleWin.exe maybe relative to this! (GH#663) +std::string g_sProgramDir; // Directory of where AppleWin executable resides +std::string g_sCurrentDir; // Also Starting Dir. Debugger uses this when load/save + +bool g_bRestart = false; + +bool g_bDisableDirectInput = false; +bool g_bDisableDirectSound = false; +bool g_bDisableDirectSoundMockingboard = false; + +DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar +double g_fCurrentCLK6502 = CLK_6502_NTSC; // Affected by Config dialog's speed slider bar +static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar + +int g_nCpuCyclesFeedback = 0; +DWORD g_dwCyclesThisFrame = 0; + +int g_nMemoryClearType = MIP_FF_FF_00_00; // Note: -1 = random MIP in Memory.cpp MemReset() + +SynchronousEventManager g_SynchronousEventMgr; + +IPropertySheet& sg_PropertySheet = *new CPropertySheet; + +HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom F8 ROM at $F800..$FFFF +bool g_bCustomRomF8Failed = false; // Set if custom F8 ROM file failed +HANDLE g_hCustomRom = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $C000..$FFFF(16KiB) or $D000..$FFFF(12KiB) +bool g_bCustomRomFailed = false; // Set if custom ROM file failed + +bool g_bEnableSpeech = false; +#ifdef USE_SPEECH_API +CSpeech g_Speech; +#endif + +//=========================================================================== + +#ifdef LOG_PERF_TIMINGS +static UINT64 g_timeTotal = 0; +UINT64 g_timeCpu = 0; +UINT64 g_timeVideo = 0; // part of timeCpu +UINT64 g_timeMB_Timer = 0; // part of timeCpu +UINT64 g_timeMB_NoTimer = 0; +UINT64 g_timeSpeaker = 0; +static UINT64 g_timeVideoRefresh = 0; + +void LogPerfTimings(void) +{ + if (g_timeTotal) + { + UINT64 cpu = g_timeCpu - g_timeVideo - g_timeMB_Timer; + UINT64 video = g_timeVideo + g_timeVideoRefresh; + UINT64 spkr = g_timeSpeaker; + UINT64 mb = g_timeMB_Timer + g_timeMB_NoTimer; + UINT64 audio = spkr + mb; + UINT64 other = g_timeTotal - g_timeCpu - g_timeSpeaker - g_timeMB_NoTimer - g_timeVideoRefresh; + + LogOutput("Perf breakdown:\n"); + LogOutput(". CPU %% = %6.2f\n", (double)cpu / (double)g_timeTotal * 100.0); + LogOutput(". Video %% = %6.2f\n", (double)video / (double)g_timeTotal * 100.0); + LogOutput("... NTSC %% = %6.2f\n", (double)g_timeVideo / (double)g_timeTotal * 100.0); + LogOutput("... refresh %% = %6.2f\n", (double)g_timeVideoRefresh / (double)g_timeTotal * 100.0); + LogOutput(". Audio %% = %6.2f\n", (double)audio / (double)g_timeTotal * 100.0); + LogOutput("... Speaker %% = %6.2f\n", (double)spkr / (double)g_timeTotal * 100.0); + LogOutput("... MB %% = %6.2f\n", (double)mb / (double)g_timeTotal * 100.0); + LogOutput(". Other %% = %6.2f\n", (double)other / (double)g_timeTotal * 100.0); + LogOutput(". TOTAL %% = %6.2f\n", (double)(cpu+video+audio+other) / (double)g_timeTotal * 100.0); + } +} +#endif + +//=========================================================================== + +static DWORD dwLogKeyReadTickStart; +static bool bLogKeyReadDone = false; + +void LogFileTimeUntilFirstKeyReadReset(void) +{ +#ifdef LOG_PERF_TIMINGS + LogPerfTimings(); +#endif + + if (!g_fh) + return; + + dwLogKeyReadTickStart = GetTickCount(); + + bLogKeyReadDone = false; +} + +// Log the time from emulation restart/reboot until the first key read: BIT $C000 +// . AZTEC.DSK (DOS 3.3) does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message +// . Phasor1.dsk / ProDOS 1.1.1: PC=E797: B1 50: LDA ($50),Y / "Select an Option:" message +// . Rescue Raiders v1.3,v1.5: PC=895: LDA $C000 / boot to intro +void LogFileTimeUntilFirstKeyRead(void) +{ + if (!g_fh || bLogKeyReadDone) + return; + + if ( (mem[regs.pc-3] != 0x2C) // AZTEC: bit $c000 + && !((regs.pc-2) == 0xE797 && mem[regs.pc-2] == 0xB1 && mem[regs.pc-1] == 0x50) // Phasor1: lda ($50),y + && !((regs.pc-3) == 0x0895 && mem[regs.pc-3] == 0xAD) // Rescue Raiders v1.3,v1.5: lda $c000 + ) + return; + + DWORD dwTime = GetTickCount() - dwLogKeyReadTickStart; + + LogFileOutput("Time from emulation reboot until first $C000 access: %d msec\n", dwTime); + + bLogKeyReadDone = true; +} + +//--------------------------------------------------------------------------- + +eApple2Type GetApple2Type(void) +{ + return g_Apple2Type; +} + +void SetApple2Type(eApple2Type type) +{ + g_Apple2Type = type; + SetMainCpuDefault(type); +} + +const UINT16* GetOldAppleWinVersion(void) +{ + return g_OldAppleWinVersion; +} + +CardManager& GetCardMgr(void) +{ + static CardManager g_CardMgr; // singleton + return g_CardMgr; +} + +//=========================================================================== + +double Get6502BaseClock(void) +{ + return (GetVideoRefreshRate() == VR_50HZ) ? CLK_6502_PAL : CLK_6502_NTSC; +} + +void SetCurrentCLK6502(void) +{ + static DWORD dwPrevSpeed = (DWORD) -1; + static VideoRefreshRate_e prevVideoRefreshRate = VR_NONE; + + if (dwPrevSpeed == g_dwSpeed && GetVideoRefreshRate() == prevVideoRefreshRate) + return; + + dwPrevSpeed = g_dwSpeed; + prevVideoRefreshRate = GetVideoRefreshRate(); + + // SPEED_MIN = 0 = 0.50 MHz + // SPEED_NORMAL = 10 = 1.00 MHz + // 20 = 2.00 MHz + // SPEED_MAX-1 = 39 = 3.90 MHz + // SPEED_MAX = 40 = ???? MHz (run full-speed, /g_fCurrentCLK6502/ is ignored) + + if(g_dwSpeed < SPEED_NORMAL) + g_fMHz = 0.5 + (double)g_dwSpeed * 0.05; + else + g_fMHz = (double)g_dwSpeed / 10.0; + + g_fCurrentCLK6502 = Get6502BaseClock() * g_fMHz; + + // + // Now re-init modules that are dependent on /g_fCurrentCLK6502/ + // + + SpkrReinitialize(); + MB_Reinitialize(); +} + +void UseClockMultiplier(double clockMultiplier) +{ + if (clockMultiplier == 0.0) + return; + + if (clockMultiplier < 1.0) + { + if (clockMultiplier < 0.5) + clockMultiplier = 0.5; + g_dwSpeed = (ULONG)((clockMultiplier - 0.5) * 20); // [0.5..0.9] -> [0..9] + } + else + { + g_dwSpeed = (ULONG)(clockMultiplier * 10); + if (g_dwSpeed >= SPEED_MAX) + g_dwSpeed = SPEED_MAX - 1; + } + + SetCurrentCLK6502(); +} + +void SetAppleWinVersion(UINT16 major, UINT16 minor, UINT16 fix, UINT16 fix_minor) +{ + g_AppleWinVersion[0] = major; + g_AppleWinVersion[1] = minor; + g_AppleWinVersion[2] = fix; + g_AppleWinVersion[3] = fix_minor; + StringCbPrintf(VERSIONSTRING, VERSIONSTRING_SIZE, "%d.%d.%d.%d", major, minor, fix, fix_minor); +} + +bool CheckOldAppleWinVersion(void) +{ + TCHAR szOldAppleWinVersion[VERSIONSTRING_SIZE + 1]; + RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, VERSIONSTRING_SIZE, TEXT("")); + const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0; + + // version: xx.yy.zz.ww + char* p0 = szOldAppleWinVersion; + int len = strlen(szOldAppleWinVersion); + szOldAppleWinVersion[len] = '.'; // append a null terminator + szOldAppleWinVersion[len + 1] = '\0'; + for (UINT i = 0; i < 4; i++) + { + char* p1 = strstr(p0, "."); + if (!p1) + break; + *p1 = 0; + g_OldAppleWinVersion[i] = atoi(p0); + p0 = p1 + 1; + } + + return bShowAboutDlg; +} + +bool SetCurrentImageDir(const std::string& pszImageDir) +{ + g_sCurrentDir = pszImageDir; + + if (!g_sCurrentDir.empty() && *g_sCurrentDir.rbegin() != '\\') + g_sCurrentDir += '\\'; + + if (SetCurrentDirectory(g_sCurrentDir.c_str())) + return true; + + return false; +} diff --git a/source/AppleWin.h b/source/Core.h similarity index 70% rename from source/AppleWin.h rename to source/Core.h index 18f12e8a..7eb8d34d 100644 --- a/source/AppleWin.h +++ b/source/Core.h @@ -1,17 +1,17 @@ #pragma once #include "Card.h" -#include "SaveState_Structs_common.h" #include "Common.h" void LogFileTimeUntilFirstKeyReadReset(void); void LogFileTimeUntilFirstKeyRead(void); -bool SetCurrentImageDir(const std::string & pszImageDir); - extern const UINT16* GetOldAppleWinVersion(void); extern TCHAR VERSIONSTRING[]; // Constructed in WinMain() +void SetAppleWinVersion(UINT16 major, UINT16 minor, UINT16 fix, UINT16 fix_minor); +bool CheckOldAppleWinVersion(void); + extern std::string g_pAppTitle; extern eApple2Type g_Apple2Type; @@ -21,25 +21,25 @@ void SetApple2Type(eApple2Type type); double Get6502BaseClock(void); void SetCurrentCLK6502(void); -void SingleStep(bool bReinit); +// set g_dwSpeed = +// | clockMultiplier == 0 => unchanged +// | clockMultiplier < 1 => (max(0.5, clockMultiplier) - 0.5) * 20 +// | else => min(SPEED_MAX - 1, clockMultiplier * 10) +void UseClockMultiplier(double clockMultiplier); extern bool g_bFullSpeed; //=========================================== -// Win32 -extern HINSTANCE g_hInstance; - extern AppMode_e g_nAppMode; -bool GetLoadedSaveStateFlag(void); -void SetLoadedSaveStateFlag(const bool bFlag); -bool GetHookAltGrControl(void); +extern std::string g_sStartDir; extern std::string g_sProgramDir; extern std::string g_sCurrentDir; +bool SetCurrentImageDir(const std::string& pszImageDir); + extern bool g_bRestart; -extern bool g_bRestartFullScreen; extern DWORD g_dwSpeed; extern double g_fCurrentCLK6502; @@ -47,25 +47,27 @@ extern double g_fCurrentCLK6502; extern int g_nCpuCyclesFeedback; extern DWORD g_dwCyclesThisFrame; -extern bool g_bDisableDirectInput; // Cmd line switch: don't init DI (so no DIMouse support) -extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB/Speaker support) -extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (Memory Initialization Pattern) extern class CardManager& GetCardMgr(void); extern class SynchronousEventManager g_SynchronousEventMgr; -extern HANDLE g_hCustomRomF8; // INVALID_HANDLE_VALUE if no custom F8 rom -extern HANDLE g_hCustomRom; // INVALID_HANDLE_VALUE if no custom rom +extern HANDLE g_hCustomRomF8; // INVALID_HANDLE_VALUE if no custom F8 rom +extern bool g_bCustomRomF8Failed; // Set if custom F8 ROM file failed +extern HANDLE g_hCustomRom; // INVALID_HANDLE_VALUE if no custom rom +extern bool g_bCustomRomFailed; // Set if custom ROM file failed +extern bool g_bEnableSpeech; #ifdef USE_SPEECH_API class CSpeech; extern CSpeech g_Speech; #endif -extern __interface IPropertySheet& sg_PropertySheet; +extern bool g_bDisableDirectInput; // Cmd line switch: don't init DI (so no DIMouse support) +extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB/Speaker support) +extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support -// +extern __interface IPropertySheet& sg_PropertySheet; //#define LOG_PERF_TIMINGS #ifdef LOG_PERF_TIMINGS diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 7a5566fd..4819a5a3 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -34,7 +34,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debug.h" #include "DebugDefs.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" +#include "../Core.h" #include "../CardManager.h" #include "../CPU.h" #include "../Disk.h" diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp index 653a0c26..34ce1db2 100644 --- a/source/Debugger/Debugger_Assembler.cpp +++ b/source/Debugger/Debugger_Assembler.cpp @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../CPU.h" #include "../Memory.h" +#include "../Windows/WinFrame.h" #define DEBUG_ASSEMBLER 0 diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index cdc391ec..f2ac73f4 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -32,7 +32,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debug.h" #include "Debugger_Display.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" +#include "../Core.h" #include "../CPU.h" #include "../Frame.h" #include "../Windows/WinFrame.h" diff --git a/source/Debugger/Debugger_Help.cpp b/source/Debugger/Debugger_Help.cpp index c81bd20f..97e097bb 100644 --- a/source/Debugger/Debugger_Help.cpp +++ b/source/Debugger/Debugger_Help.cpp @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debug.h" -#include "../AppleWin.h" +#include "../Core.h" #define DEBUG_COLOR_CONSOLE 0 diff --git a/source/Debugger/Debugger_Symbols.cpp b/source/Debugger/Debugger_Symbols.cpp index 5f5e0160..a168d6cd 100644 --- a/source/Debugger/Debugger_Symbols.cpp +++ b/source/Debugger/Debugger_Symbols.cpp @@ -30,7 +30,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debug.h" -#include "../AppleWin.h" +#include "../Windows/AppleWin.h" +#include "../Core.h" // 2.6.2.13 Added: Can now enable/disable selected symbol table(s) ! // Allow the user to disable/enable symbol tables diff --git a/source/Disk.cpp b/source/Disk.cpp index 7090a0d2..329848d8 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -34,7 +34,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "SaveState_Structs_v1.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" +#include "Core.h" #include "CPU.h" #include "DiskImage.h" #include "Log.h" diff --git a/source/Disk2CardManager.cpp b/source/Disk2CardManager.cpp index 11122242..0139bbbe 100644 --- a/source/Disk2CardManager.cpp +++ b/source/Disk2CardManager.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Disk2CardManager.h" -#include "AppleWin.h" +#include "Core.h" #include "CardManager.h" #include "Disk.h" diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index 5dbe3b2a..202725d7 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" +#include "Core.h" #include "DiskImageHelper.h" #include "Common.h" @@ -2199,8 +2200,6 @@ UINT CHardDiskImageHelper::GetMinDetectSize(const UINT uImageSize, bool* pTempDe #define ASSERT_OFFSET(x, offset) _ASSERT( ((BYTE*)&pWOZ->x - (BYTE*)pWOZ) == offset ) -extern TCHAR VERSIONSTRING[]; // AppleWin.h - BYTE* CWOZHelper::CreateEmptyDisk(DWORD& size) { WOZEmptyImage525* pWOZ = new WOZEmptyImage525; diff --git a/source/Harddisk.cpp b/source/Harddisk.cpp index 1c6bb4a2..0631ba01 100644 --- a/source/Harddisk.cpp +++ b/source/Harddisk.cpp @@ -29,7 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Harddisk.h" -#include "AppleWin.h" +#include "Core.h" +#include "Windows/AppleWin.h" #include "CardManager.h" #include "CPU.h" #include "DiskImage.h" // ImageError_e, Disk_Status_e diff --git a/source/Joystick.cpp b/source/Joystick.cpp index 7441c288..ee65b5d5 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Joystick.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" #include "CPU.h" #include "Memory.h" #include "YamlHelper.h" diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index dd81c9b6..bb814f52 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -29,7 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Keyboard.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" +#include "Core.h" #include "Windows/WinFrame.h" #include "Pravets.h" #include "Tape.h" diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp index 15efb773..a362e8df 100644 --- a/source/LanguageCard.cpp +++ b/source/LanguageCard.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "LanguageCard.h" -#include "AppleWin.h" +#include "Core.h" #include "CPU.h" // GH#700 #include "Log.h" #include "Memory.h" diff --git a/source/Memory.cpp b/source/Memory.cpp index 88df89da..cbfe9918 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Memory.h" -#include "AppleWin.h" +#include "Core.h" #include "CardManager.h" #include "CPU.h" #include "Disk.h" diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 8a152905..0f6daa0a 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -80,7 +80,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Mockingboard.h" #include "SaveState_Structs_v1.h" -#include "AppleWin.h" +#include "Core.h" #include "CardManager.h" #include "CPU.h" #include "Log.h" diff --git a/source/MouseInterface.cpp b/source/MouseInterface.cpp index b1725b22..95ef2956 100644 --- a/source/MouseInterface.cpp +++ b/source/MouseInterface.cpp @@ -46,7 +46,7 @@ Etc. #include "SaveState_Structs_common.h" #include "Common.h" -#include "AppleWin.h" // g_SynchronousEventMgr +#include "Core.h" // g_SynchronousEventMgr #include "CardManager.h" #include "CPU.h" #include "Windows/WinFrame.h" // FrameSetCursorPosByMousePos() diff --git a/source/NTSC.cpp b/source/NTSC.cpp index c96aa418..f54d3537 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Includes #include "StdAfx.h" #include "NTSC.h" - #include "AppleWin.h" + #include "Core.h" #include "CPU.h" // CpuGetCyclesThisVideoFrame() #include "Frame.h" #include "Memory.h" // MemGetMainPtr(), MemGetAuxPtr(), MemGetAnnunciator() diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 745c1032..70be74c1 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -21,7 +21,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "NTSC_CharSet.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" +#include "Core.h" #include "../resource/resource.h" #include "Video.h" diff --git a/source/ParallelPrinter.cpp b/source/ParallelPrinter.cpp index 6c1b90bd..49ab174e 100644 --- a/source/ParallelPrinter.cpp +++ b/source/ParallelPrinter.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "ParallelPrinter.h" -#include "AppleWin.h" +#include "Core.h" #include "Memory.h" #include "Registry.h" #include "YamlHelper.h" diff --git a/source/Pravets.cpp b/source/Pravets.cpp index 0e65f2c8..70f97f1d 100644 --- a/source/Pravets.cpp +++ b/source/Pravets.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Pravets.h" -#include "AppleWin.h" +#include "Core.h" #include "Windows/WinFrame.h" #include "Keyboard.h" #include "Tape.h" diff --git a/source/Registry.cpp b/source/Registry.cpp index 59ea7483..f543bea0 100644 --- a/source/Registry.cpp +++ b/source/Registry.cpp @@ -29,8 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Registry.h" - -extern std::string g_sConfigFile; +#include "CmdLine.h" namespace _ini { //=========================================================================== diff --git a/source/SAM.cpp b/source/SAM.cpp index 19b684a8..8394d3b5 100644 --- a/source/SAM.cpp +++ b/source/SAM.cpp @@ -33,7 +33,6 @@ #include "StdAfx.h" #include "SAM.h" -#include "AppleWin.h" #include "Memory.h" #include "Speaker.h" diff --git a/source/SaveState.cpp b/source/SaveState.cpp index d339d870..311565cb 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "SaveState.h" #include "YamlHelper.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" #include "CardManager.h" #include "CPU.h" #include "Debug.h" diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index 6ded02ad..0f00c546 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -36,7 +36,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "SerialComms.h" -#include "AppleWin.h" #include "CPU.h" #include "Windows/WinFrame.h" #include "Log.h" diff --git a/source/SoundCore.cpp b/source/SoundCore.cpp index 5209ee4c..2f224e82 100644 --- a/source/SoundCore.cpp +++ b/source/SoundCore.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "SoundCore.h" -#include "AppleWin.h" +#include "Core.h" #include "Windows/WinFrame.h" #include "Log.h" #include "Speaker.h" diff --git a/source/Speaker.cpp b/source/Speaker.cpp index 8f0ec69f..2d8740ef 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Speaker.h" -#include "AppleWin.h" +#include "Core.h" #include "CPU.h" #include "Windows/WinFrame.h" #include "Log.h" diff --git a/source/SynchronousEventManager.cpp b/source/SynchronousEventManager.cpp index ceba4a9b..3ad1dfeb 100644 --- a/source/SynchronousEventManager.cpp +++ b/source/SynchronousEventManager.cpp @@ -42,7 +42,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "SynchronousEventManager.h" -#include "AppleWin.h" void SynchronousEventManager::Insert(SyncEvent* pNewEvent) { diff --git a/source/Tape.cpp b/source/Tape.cpp index f597ef7c..930f2b5b 100644 --- a/source/Tape.cpp +++ b/source/Tape.cpp @@ -32,7 +32,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Tape.h" -#include "AppleWin.h" #include "Keyboard.h" #include "Memory.h" #include "Pravets.h" diff --git a/source/Utilities.cpp b/source/Utilities.cpp new file mode 100644 index 00000000..b9ece845 --- /dev/null +++ b/source/Utilities.cpp @@ -0,0 +1,455 @@ +/*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 "Utilities.h" +#include "Core.h" +#include "CardManager.h" +#include "CPU.h" +#include "Video.h" +#include "Joystick.h" +#include "Log.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 "Mockingboard.h" +#include "Windows/WinFrame.h" + +#include "Configuration/PropertySheet.h" +#include "Tfe/Tfe.h" + +// Backwards compatibility with AppleWin <1.24.0 +static void LoadConfigOldJoystick_v1(const UINT uJoyNum) +{ + DWORD dwOldJoyType; + if (!REGLOAD(TEXT(uJoyNum==0 ? REGVALUE_OLD_JOYSTICK0_EMU_TYPE1 : REGVALUE_OLD_JOYSTICK1_EMU_TYPE1), &dwOldJoyType)) + return; // EG. Old AppleWin never installed + + UINT uNewJoyType; + switch (dwOldJoyType) + { + case 0: // Disabled + default: + uNewJoyType = J0C_DISABLED; + break; + case 1: // PC Joystick + uNewJoyType = J0C_JOYSTICK1; + break; + case 2: // Keyboard (standard) + uNewJoyType = J0C_KEYBD_NUMPAD; + sg_PropertySheet.SetJoystickCenteringControl(JOYSTICK_MODE_FLOATING); + break; + case 3: // Keyboard (centering) + uNewJoyType = J0C_KEYBD_NUMPAD; + sg_PropertySheet.SetJoystickCenteringControl(JOYSTICK_MODE_CENTERING); + break; + case 4: // Mouse + uNewJoyType = J0C_MOUSE; + break; + } + + JoySetJoyType(uJoyNum, uNewJoyType); +} + +//Reads configuration from the registry entries +void LoadConfiguration(void) +{ + DWORD dwComputerType = 0; + eApple2Type apple2Type = A2TYPE_APPLE2EENHANCED; + + if (REGLOAD(TEXT(REGVALUE_APPLE2_TYPE), &dwComputerType)) + { + const DWORD dwLoadedComputerType = dwComputerType; + + if ( (dwComputerType >= A2TYPE_MAX) || + (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE) || + (dwComputerType >= A2TYPE_CLONE_A2_MAX && dwComputerType < A2TYPE_CLONE_A2E) ) + dwComputerType = A2TYPE_APPLE2EENHANCED; + + // Remap the bad Pravets models (before AppleWin v1.26) + if (dwComputerType == A2TYPE_BAD_PRAVETS82) dwComputerType = A2TYPE_PRAVETS82; + if (dwComputerType == A2TYPE_BAD_PRAVETS8M) dwComputerType = A2TYPE_PRAVETS8M; + + // Remap the bad Pravets models (at AppleWin v1.26) - GH#415 + if (dwComputerType == A2TYPE_CLONE) dwComputerType = A2TYPE_PRAVETS82; + + if (dwLoadedComputerType != dwComputerType) + { + char sText[100]; + StringCbPrintf(sText, sizeof(sText), "Unsupported Apple2Type(%d). Changing to %d", dwLoadedComputerType, dwComputerType); + + LogFileOutput("%s\n", sText); + + MessageBox( + GetDesktopWindow(), // NB. g_hFrameWindow is not yet valid + sText, + "Load Configuration", + MB_ICONSTOP | MB_SETFOREGROUND); + + sg_PropertySheet.ConfigSaveApple2Type((eApple2Type)dwComputerType); + } + + apple2Type = (eApple2Type) dwComputerType; + } + else if (REGLOAD(TEXT(REGVALUE_OLD_APPLE2_TYPE), &dwComputerType)) // Support older AppleWin registry entries + { + switch (dwComputerType) + { + // NB. No A2TYPE_APPLE2E (this is correct) + case 0: apple2Type = A2TYPE_APPLE2; break; + case 1: apple2Type = A2TYPE_APPLE2PLUS; break; + case 2: apple2Type = A2TYPE_APPLE2EENHANCED; break; + default: apple2Type = A2TYPE_APPLE2EENHANCED; break; + } + } + + SetApple2Type(apple2Type); + + // + + DWORD dwMainCpuType; + REGLOAD_DEFAULT(TEXT(REGVALUE_CPU_TYPE), &dwMainCpuType, CPU_65C02); + if (dwMainCpuType != CPU_6502 && dwMainCpuType != CPU_65C02) + dwMainCpuType = CPU_65C02; + SetMainCpu((eCpuType)dwMainCpuType); + + // + + DWORD dwJoyType; + if (REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK0, dwJoyType); + else if (REGLOAD(TEXT(REGVALUE_OLD_JOYSTICK0_EMU_TYPE2), &dwJoyType)) // GH#434 + JoySetJoyType(JN_JOYSTICK0, dwJoyType); + else + LoadConfigOldJoystick_v1(JN_JOYSTICK0); + + if (REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &dwJoyType)) + JoySetJoyType(JN_JOYSTICK1, dwJoyType); + else if (REGLOAD(TEXT(REGVALUE_OLD_JOYSTICK1_EMU_TYPE2), &dwJoyType)) // GH#434 + JoySetJoyType(JN_JOYSTICK1, dwJoyType); + else + LoadConfigOldJoystick_v1(JN_JOYSTICK1); + + DWORD dwSoundType; + REGLOAD_DEFAULT(TEXT(REGVALUE_SOUND_EMULATION), &dwSoundType, REG_SOUNDTYPE_WAVE); + switch (dwSoundType) + { + case REG_SOUNDTYPE_NONE: + case REG_SOUNDTYPE_DIRECT: // Not supported from 1.26 + case REG_SOUNDTYPE_SMART: // Not supported from 1.26 + default: + soundtype = SOUND_NONE; + break; + case REG_SOUNDTYPE_WAVE: + soundtype = SOUND_WAVE; + break; + } + + TCHAR serialPortName[CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM]; + if (RegLoadString( + TEXT(REG_CONFIG), + TEXT(REGVALUE_SERIAL_PORT_NAME), + TRUE, + serialPortName, + CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM)) + { + if (GetCardMgr().IsSSCInstalled()) + GetCardMgr().GetSSC()->SetSerialPortName(serialPortName); + } + + REGLOAD_DEFAULT(TEXT(REGVALUE_EMULATION_SPEED), &g_dwSpeed, SPEED_NORMAL); + Config_Load_Video(); + SetCurrentCLK6502(); // Pre: g_dwSpeed && Config_Load_Video()->SetVideoRefreshRate() + + DWORD dwEnhanceDisk; + REGLOAD_DEFAULT(TEXT(REGVALUE_ENHANCE_DISK_SPEED), &dwEnhanceDisk, 1); + GetCardMgr().GetDisk2CardMgr().SetEnhanceDisk(dwEnhanceDisk ? true : false); + + // + + DWORD dwTmp = 0; + + if(REGLOAD(TEXT(REGVALUE_FS_SHOW_SUBUNIT_STATUS), &dwTmp)) + SetFullScreenShowSubunitStatus(dwTmp ? true : false); + + if(REGLOAD(TEXT(REGVALUE_THE_FREEZES_F8_ROM), &dwTmp)) + sg_PropertySheet.SetTheFreezesF8Rom(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp)) + SpkrSetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); + + if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp)) + MB_SetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); + + if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp)) + g_bSaveStateOnExit = dwTmp ? true : false; + + + if(REGLOAD(TEXT(REGVALUE_DUMP_TO_PRINTER), &dwTmp)) + g_bDumpToPrinter = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_CONVERT_ENCODING), &dwTmp)) + g_bConvertEncoding = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_FILTER_UNPRINTABLE), &dwTmp)) + g_bFilterUnprintable = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_PRINTER_APPEND), &dwTmp)) + g_bPrinterAppend = dwTmp ? true : false; + + + if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) // TODO: Change to REGVALUE_SLOT7 + HD_SetEnabled(dwTmp ? true : false); + + if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) + JoySetTrim((short)dwTmp, true); + if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) + JoySetTrim((short)dwTmp, false); + + if(REGLOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp)) + sg_PropertySheet.SetScrollLockToggle(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_CURSOR_CONTROL), &dwTmp)) + sg_PropertySheet.SetJoystickCursorControl(dwTmp); + if(REGLOAD(TEXT(REGVALUE_AUTOFIRE), &dwTmp)) + sg_PropertySheet.SetAutofire(dwTmp); + if(REGLOAD(TEXT(REGVALUE_SWAP_BUTTONS_0_AND_1), &dwTmp)) + sg_PropertySheet.SetButtonsSwapState(dwTmp ? true : false); + if(REGLOAD(TEXT(REGVALUE_CENTERING_CONTROL), &dwTmp)) + sg_PropertySheet.SetJoystickCenteringControl(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_MOUSE_CROSSHAIR), &dwTmp)) + sg_PropertySheet.SetMouseShowCrosshair(dwTmp); + if(REGLOAD(TEXT(REGVALUE_MOUSE_RESTRICT_TO_WINDOW), &dwTmp)) + sg_PropertySheet.SetMouseRestrictToWindow(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp)) + GetCardMgr().Insert(4, (SS_CARDTYPE)dwTmp); + if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp)) + GetCardMgr().Insert(5, (SS_CARDTYPE)dwTmp); + + // + + TCHAR szFilename[MAX_PATH]; + + // Load save-state pathname *before* inserting any harddisk/disk images (for both init & reinit cases) + // NB. inserting harddisk/disk can change snapshot pathname + RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_SAVESTATE_FILENAME), 1, szFilename, MAX_PATH, TEXT("")); // Can be pathname or just filename + Snapshot_SetFilename(szFilename); // If not in Registry than default will be used (ie. g_sCurrentDir + default filename) + + // + + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_HDV_START_DIR), 1, szFilename, MAX_PATH, TEXT("")); + if (szFilename[0] == '\0') + GetCurrentDirectory(sizeof(szFilename), szFilename); + SetCurrentImageDir(szFilename); + + HD_LoadLastDiskImage(HARDDISK_1); + HD_LoadLastDiskImage(HARDDISK_2); + + // + + // Current/Starting Dir is the "root" of where the user keeps their disk images + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH, TEXT("")); + if (szFilename[0] == '\0') + GetCurrentDirectory(sizeof(szFilename), szFilename); + SetCurrentImageDir(szFilename); + + GetCardMgr().GetDisk2CardMgr().LoadLastDiskImage(); + + // + + DWORD dwTfeEnabled; + REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &dwTfeEnabled, 0); + tfe_enabled = dwTfeEnabled ? 1 : 0; + + RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT("")); + update_tfe_interface(szFilename, NULL); + + // + + RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_PRINTER_FILENAME), 1, szFilename, MAX_PATH, TEXT("")); + Printer_SetFilename(szFilename); // If not in Registry than default will be used + + REGLOAD_DEFAULT(TEXT(REGVALUE_PRINTER_IDLE_LIMIT), &dwTmp, 10); + Printer_SetIdleLimit(dwTmp); + + if (REGLOAD(TEXT(REGVALUE_WINDOW_SCALE), &dwTmp)) + SetViewportScale(dwTmp); + + if (REGLOAD(TEXT(REGVALUE_CONFIRM_REBOOT), &dwTmp)) + g_bConfirmReboot = dwTmp; +} + +static std::string GetFullPath(LPCSTR szFileName) +{ + std::string strPathName; + + if (szFileName[0] == '\\' || szFileName[1] == ':') + { + // Abs pathname + strPathName = szFileName; + } + else + { + // Rel pathname (GH#663) + strPathName = g_sStartDir; + strPathName.append(szFileName); + } + + return strPathName; +} + +static void SetCurrentDir(std::string pathname) +{ + // Due to the order HDDs/disks are inserted, then s7 insertions take priority over s6 & s5; and d2 takes priority over d1: + // . if -s6[dN] and -hN are specified, then g_sCurrentDir will be set to the HDD image's path + // . if -s5[dN] and -s6[dN] are specified, then g_sCurrentDir will be set to the s6 image's path + // . if -[sN]d1 and -[sN]d2 are specified, then g_sCurrentDir will be set to the d2 image's path + // This is purely dependent on the current order of InsertFloppyDisks() & InsertHardDisks() - ie. very brittle! + // . better to use -current-dir to be explicit + std::size_t found = pathname.find_last_of("\\"); + std::string path = pathname.substr(0, found); + SetCurrentImageDir(path); +} + +bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName) +{ + Disk2InterfaceCard& disk2Card = dynamic_cast(GetCardMgr().GetRef(slot)); + + if (szFileName[0] == '\0') + { + disk2Card.EjectDisk(nDrive); + return true; + } + + std::string strPathName = GetFullPath(szFileName); + if (strPathName.empty()) return false; + + ImageError_e Error = disk2Card.InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); + bool res = (Error == eIMAGE_ERROR_NONE); + if (res) + SetCurrentDir(strPathName); + return res; +} + +bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName) +{ + if (szFileName[0] == '\0') + { + HD_Unplug(nDrive); + return true; + } + + std::string strPathName = GetFullPath(szFileName); + if (strPathName.empty()) return false; + + BOOL bRes = HD_Insert(nDrive, strPathName.c_str()); + bool res = (bRes == TRUE); + if (res) + SetCurrentDir(strPathName); + return res; +} + +void InsertFloppyDisks(const UINT slot, LPSTR szImageName_drive[NUM_DRIVES], bool& bBoot) +{ + _ASSERT(slot == 5 || slot == 6); + + if (!szImageName_drive[DRIVE_1] && !szImageName_drive[DRIVE_2]) + return; + + bool bRes = true; + + if (szImageName_drive[DRIVE_1]) + { + bRes = DoDiskInsert(slot, DRIVE_1, szImageName_drive[DRIVE_1]); + LogFileOutput("Init: S%d, DoDiskInsert(D1), res=%d\n", slot, bRes); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); // floppy activity LEDs and floppy buttons + bBoot = true; + } + + if (szImageName_drive[DRIVE_2]) + { + bRes |= DoDiskInsert(slot, DRIVE_2, szImageName_drive[DRIVE_2]); + LogFileOutput("Init: S%d, DoDiskInsert(D2), res=%d\n", slot, bRes); + } + + if (!bRes) + MessageBox(g_hFrameWindow, "Failed to insert floppy disk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK); +} + +void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBoot) +{ + if (!szImageName_harddisk[HARDDISK_1] && !szImageName_harddisk[HARDDISK_2]) + return; + + // Enable the Harddisk controller card + + HD_SetEnabled(true); + + DWORD dwTmp; + BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); + if (!res || !dwTmp) + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled + + // + + bool bRes = true; + + if (szImageName_harddisk[HARDDISK_1]) + { + bRes = DoHardDiskInsert(HARDDISK_1, szImageName_harddisk[HARDDISK_1]); + LogFileOutput("Init: DoHardDiskInsert(HDD1), res=%d\n", bRes); + FrameRefreshStatus(DRAW_LEDS); // harddisk activity LED + bBoot = true; + } + + if (szImageName_harddisk[HARDDISK_2]) + { + bRes |= DoHardDiskInsert(HARDDISK_2, szImageName_harddisk[HARDDISK_2]); + LogFileOutput("Init: DoHardDiskInsert(HDD2), res=%d\n", bRes); + } + + if (!bRes) + MessageBox(g_hFrameWindow, "Failed to insert harddisk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK); +} + +void UnplugHardDiskControllerCard(void) +{ + HD_SetEnabled(false); + + DWORD dwTmp; + BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); + if (!res || dwTmp) + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled +} diff --git a/source/Utilities.h b/source/Utilities.h new file mode 100644 index 00000000..afeb6559 --- /dev/null +++ b/source/Utilities.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Disk.h" +#include "Harddisk.h" + + +void LoadConfiguration(); +bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName); +bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName); +void InsertFloppyDisks(const UINT slot, LPSTR szImageName_drive[NUM_DRIVES], bool& bBoot); +void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBoot); +void UnplugHardDiskControllerCard(void); diff --git a/source/Video.cpp b/source/Video.cpp index 5dbe76d4..06f5024f 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Video.h" -#include "AppleWin.h" +#include "Core.h" #include "CPU.h" #include "Frame.h" #include "Windows/WinFrame.h" diff --git a/source/Windows/AppleWin.cpp b/source/Windows/AppleWin.cpp new file mode 100644 index 00000000..91a66d7d --- /dev/null +++ b/source/Windows/AppleWin.cpp @@ -0,0 +1,1048 @@ +/* +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 "Utilities.h" +#include "CmdLine.h" +#include "Debug.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 "SoundCore.h" +#include "Speaker.h" +#ifdef USE_SPEECH_API +#include "Speech.h" +#endif +#include "Windows/WinVideo.h" +#include "Windows/WinFrame.h" +#include "RGBMonitor.h" +#include "NTSC.h" + +#include "Configuration/About.h" +#include "Configuration/PropertySheet.h" +#include "Tfe/Tfe.h" + +//================================================= + +// Win32 +HINSTANCE g_hInstance = (HINSTANCE)0; + +static bool g_bLoadedSaveState = false; +static bool g_bSysClkOK = false; + +bool g_bRestartFullScreen = false; + +//=========================================================================== + +bool GetLoadedSaveStateFlag(void) +{ + return g_bLoadedSaveState; +} + +void SetLoadedSaveStateFlag(const bool bFlag) +{ + g_bLoadedSaveState = bFlag; +} + +bool GetHookAltGrControl(void) +{ + return g_bHookAltGrControl; +} + +static void ResetToLogoMode(void) +{ + g_nAppMode = MODE_LOGO; + 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 (sg_PropertySheet.GetScrollLockToggle()) + { + bScrollLock_FullSpeed = 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() && !MB_IsActive()) || + IsDebugSteppingAtFullSpeed(); + + if (g_bFullSpeed) + { + if (!bWasFullSpeed) + VideoRedrawScreenDuringFullSpeed(0, true); // Init for full-speed mode + + // Don't call Spkr_Mute() - will get speaker clicks + MB_Mute(); + 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) + VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame); + + // Don't call Spkr_Demute() + MB_Demute(); + 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 DWORD uCyclesToExecute = (g_nAppMode == MODE_RUNNING) ? uCyclesToExecuteWithFeedback + /* MODE_STEPPING */ : 0; + + const bool bVideoUpdate = !g_bFullSpeed; + const DWORD uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate); + g_dwCyclesThisFrame += uActualCyclesExecuted; + + GetCardMgr().GetDisk2CardMgr().UpdateDriveState(uActualCyclesExecuted); + JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency + PrintUpdate(uActualCyclesExecuted); + MB_PeriodicUpdate(uActualCyclesExecuted); + + // + + DWORD 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 && !VideoGetVblBarEx(g_dwCyclesThisFrame)) + { +#ifdef LOG_PERF_TIMINGS + PerfMarker perfMarkerVideoRefresh(g_timeVideoRefresh); +#endif + g_dwCyclesThisFrame -= dwClksPerFrame; + + if (g_bFullSpeed) + VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame); + else + VideoRefreshScreen(); // 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) +{ + TCHAR programDir[MAX_PATH]; + GetModuleFileName((HINSTANCE)0, programDir, MAX_PATH); + programDir[MAX_PATH-1] = 0; + + g_sProgramDir = programDir; + + int loop = g_sProgramDir.size(); + while (loop--) + { + if ((g_sProgramDir[loop] == TEXT('\\')) || (g_sProgramDir[loop] == TEXT(':'))) + { + g_sProgramDir.resize(loop + 1); // this reduces the size + break; + } + } +} + +//=========================================================================== + +void RegisterExtensions(void) +{ + TCHAR szCommandTmp[MAX_PATH]; + GetModuleFileName((HMODULE)0,szCommandTmp,MAX_PATH); + + TCHAR command[MAX_PATH]; + wsprintf(command, "\"%s\"", szCommandTmp); // Wrap path & filename in quotes & null terminate + + TCHAR icon[MAX_PATH]; + wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command); + + _tcscat(command,TEXT(" \"%1\"")); // Append "%1" +// _tcscat(command,TEXT("-d1 %1\"")); // Append "%1" +// sprintf(command, "\"%s\" \"-d1 %%1\"", szCommandTmp); // Wrap path & filename in quotes & null terminate + + // 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,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,_tcslen(command)+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",_tcslen("applewin")+1); +// REG_SZ,szCommandTmp,_tcslen(szCommandTmp)+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",_tcslen("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( + g_hFrameWindow , // HWND hWnd + VK_SNAPSHOT_560, // int id (user/custom id) + 0 , // UINT fsModifiers + VK_SNAPSHOT // UINT vk = PrintScreen + ); + + bStatus[1] = RegisterHotKey( + g_hFrameWindow , // HWND hWnd + VK_SNAPSHOT_280, // int id (user/custom id) + MOD_SHIFT , // UINT fsModifiers + VK_SNAPSHOT // UINT vk = PrintScreen + ); + + bStatus[2] = RegisterHotKey( + 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 (g_bShowPrintScreenWarningDialog) + MessageBox( g_hFrameWindow, msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK ); + + msg += "\n"; + LogFileOutput(msg.c_str()); + } +} + +//--------------------------------------------------------------------------- + +static HINSTANCE g_hinstDLL = 0; +static HHOOK g_hhook = 0; + +static HANDLE g_hHookThread = NULL; +static DWORD g_HookThreadId = 0; + +// Pre: g_hFrameWindow must be valid +static bool HookFilterForKeyboard() +{ + g_hinstDLL = LoadLibrary(TEXT("HookFilter.dll")); + + _ASSERT(g_hFrameWindow); + + typedef void (*RegisterHWNDProc)(HWND, bool, bool); + RegisterHWNDProc RegisterHWND = (RegisterHWNDProc) GetProcAddress(g_hinstDLL, "RegisterHWND"); + if (RegisterHWND) + RegisterHWND(g_hFrameWindow, g_bHookAltTab, g_bHookAltGrControl); + + HOOKPROC hkprcLowLevelKeyboardProc = (HOOKPROC) GetProcAddress(g_hinstDLL, "LowLevelKeyboardProc"); + + g_hhook = SetWindowsHookEx( + WH_KEYBOARD_LL, + hkprcLowLevelKeyboardProc, + g_hinstDLL, + 0); + + if (g_hhook != 0 && g_hFrameWindow != 0) + return true; + + std::string msg("Failed to install hook filter for system keys"); + + DWORD dwErr = GetLastError(); + MessageBox(GetDesktopWindow(), msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK); + + msg += "\n"; + LogFileOutput(msg.c_str()); + return false; +} + +static void UnhookFilterForKeyboard() +{ + UnhookWindowsHookEx(g_hhook); + FreeLibrary(g_hinstDLL); +} + +static DWORD WINAPI HookThread(LPVOID lpParameter) +{ + if (!HookFilterForKeyboard()) + return -1; + + MSG msg; + while(GetMessage(&msg, NULL, 0, 0) > 0) + { + if (msg.message == WM_QUIT) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + UnhookFilterForKeyboard(); + return 0; +} + +static bool InitHookThread() +{ + g_hHookThread = CreateThread(NULL, // lpThreadAttributes + 0, // dwStackSize + (LPTHREAD_START_ROUTINE) HookThread, + 0, // lpParameter + 0, // dwCreationFlags : 0 = Run immediately + &g_HookThreadId); // lpThreadId + if (g_hHookThread == NULL) + return false; + + return true; +} + +static void UninitHookThread() +{ + if (g_hHookThread) + { + if (!PostThreadMessage(g_HookThreadId, WM_QUIT, 0, 0)) + { + _ASSERT(0); + return; + } + + do + { + DWORD dwExitCode; + if (GetExitCodeThread(g_hHookThread, &dwExitCode)) + { + if(dwExitCode == STILL_ACTIVE) + Sleep(10); + else + break; + } + } + while(1); + + CloseHandle(g_hHookThread); + g_hHookThread = NULL; + g_HookThreadId = 0; + } +} + +static void ExceptionHandler(const char* pError) +{ + MessageBox( g_hFrameWindow, + pError, + TEXT("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) != '\\') g_sStartDir += '\\'; + + 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.bSetFullScreen = g_bRestartFullScreen; + g_bRestartFullScreen = false; + } + + MB_Reset(); + LogFileOutput("Main: MB_Reset()\n"); + + CMouseInterface* pMouseCard = GetCardMgr().GetMouseCard(); + if (pMouseCard) + { + pMouseCard->Reset(); // Deassert any pending IRQs - GH#514 + LogFileOutput("Main: CMouseInterface::Uninitialize()\n"); + } + + DSUninit(); + LogFileOutput("Main: DSUninit()\n"); + + if (g_bRestart) + g_SynchronousEventMgr.Reset(); + + if (g_bHookSystemKey) + { + UninitHookThread(); + LogFileOutput("Main: UnhookFilterForKeyboard()\n"); + } + } + while (g_bRestart); + } + catch(std::runtime_error exception) + { + ExceptionHandler(exception.what()); + } + catch(std::exception exception) + { + ExceptionHandler(exception.what()); + } + + Shutdown(); + 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, TEXT("\\"), (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("AppleWin version: %s\n", VERSIONSTRING); +} + +// DO ONE-TIME INITIALIZATION +static void OneTimeInitialization(HINSTANCE passinstance) +{ +#if 0 +#ifdef RIFF_SPKR + RiffInitWriteFile("Spkr.wav", SPKR_SAMPLE_RATE, 1); +#endif +#ifdef RIFF_MB + RiffInitWriteFile("Mockingboard.wav", 44100, 2); +#endif +#endif + + // Initialize COM - so we can use CoCreateInstance + // . NB. DSInit() & DIMouse::DirectInputInit are done when g_hFrameWindow is created (WM_CREATE) + 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 +#if 0 + DDInit(); // For WaitForVerticalBlank() +#endif + + g_hInstance = passinstance; + GdiSetBatchLimit(512); + LogFileOutput("Init: GdiSetBatchLimit()\n"); + + GetProgramDirectory(); + LogFileOutput("Init: GetProgramDirectory()\n"); + + if (g_bRegisterFileTypes) + { + RegisterExtensions(); + LogFileOutput("Init: RegisterExtensions()\n"); + } + + FrameRegisterClass(); + LogFileOutput("Init: FrameRegisterClass()\n"); + + ImageInitialize(); + LogFileOutput("Init: ImageInitialize()\n"); +} + +// DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART +static void RepeatInitialization(void) +{ + ResetToLogoMode(); + + // NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video() + const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion + + LoadConfiguration(); + LogFileOutput("Main: LoadConfiguration()\n"); + + if (g_cmdLine.model != A2TYPE_MAX) + SetApple2Type(g_cmdLine.model); + + RGB_SetVideocard(g_cmdLine.rgbCard, g_cmdLine.rgbCardForegroundColor, g_cmdLine.rgbCardBackgroundColor); + + if (g_cmdLine.newVideoType >= 0) + { + SetVideoType( (VideoType_e)g_cmdLine.newVideoType ); + g_cmdLine.newVideoType = -1; // Don't reapply after a restart + } + SetVideoStyle( (VideoStyle_e) ((GetVideoStyle() | g_cmdLine.newVideoStyleEnableMask) & ~g_cmdLine.newVideoStyleDisableMask) ); + + if (g_cmdLine.newVideoRefreshRate != VR_NONE) + { + 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 +#ifdef RAMWORKS + if (g_cmdLine.uRamWorksExPages) + { + SetRamWorksMemorySize(g_cmdLine.uRamWorksExPages); + SetExpansionMemType(CT_RamWorksIII); + g_cmdLine.uRamWorksExPages = 0; // Don't reapply after a restart + } +#endif + if (g_cmdLine.uSaturnBanks) + { + SetSaturnMemorySize(g_cmdLine.uSaturnBanks); // Set number of banks before constructing Saturn card + SetExpansionMemType(CT_Saturn128K); + g_cmdLine.uSaturnBanks = 0; // Don't reapply after a restart + } + + if (g_cmdLine.bSlot0LanguageCard) + { + SetExpansionMemType(CT_LanguageCard); + g_cmdLine.bSlot0LanguageCard = false; // Don't reapply after a restart + } + + if (g_cmdLine.bSwapButtons0and1) + { + sg_PropertySheet.SetButtonsSwapState(true); + // Reapply after a restart - TODO: grey-out the Config UI for "Swap 0/1" when this cmd line is passed in + } + + DebugInitialize(); + LogFileOutput("Main: DebugInitialize()\n"); + + JoyInitialize(); + LogFileOutput("Main: JoyInitialize()\n"); + + WinVideoInitialize(); // g_pFramebufferinfo been created now + LogFileOutput("Main: VideoInitialize()\n"); + + LogFileOutput("Main: FrameCreateWindow() - pre\n"); + FrameCreateWindow(); // g_hFrameWindow is now valid + LogFileOutput("Main: FrameCreateWindow() - post\n"); + + // Init palette color + VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType()); + + // Allow the 4 hardcoded slots to be configurated as empty + // NB. this state is not persisted to the Registry/conf.ini (just as '-s7 empty' isn't) + // TODO: support bSlotEmpty[] for slots: 0,4,5 + if (g_cmdLine.bSlotEmpty[SLOT1]) + GetCardMgr().Remove(SLOT1); + if (g_cmdLine.bSlotEmpty[SLOT2]) + GetCardMgr().Remove(SLOT2); + if (g_cmdLine.bSlotEmpty[SLOT3]) + GetCardMgr().Remove(SLOT3); + if (g_cmdLine.bSlotEmpty[SLOT6]) + GetCardMgr().Remove(SLOT6); + + if (g_cmdLine.slotInsert[SLOT5] != CT_Empty) + { + if (GetCardMgr().QuerySlot(SLOT4) == CT_MockingboardC && g_cmdLine.slotInsert[SLOT5] != CT_MockingboardC) // Currently MB occupies slot4+5 when enabled + { + GetCardMgr().Remove(SLOT4); + GetCardMgr().Remove(SLOT5); + } + + GetCardMgr().Insert(SLOT5, g_cmdLine.slotInsert[SLOT5]); + } + + // Pre: may need g_hFrameWindow for MessageBox errors + // Post: may enable HDD, required for MemInitialize()->MemInitializeIO() + { + bool temp = false; + InsertFloppyDisks(SLOT5, g_cmdLine.szImageName_drive[SLOT5], temp); + //g_cmdLine.szImageName_drive[SLOT5][DRIVE_1] = g_cmdLine.szImageName_drive[SLOT5][DRIVE_2] = NULL; // *Do* insert on a restart (since no way they could have changed) + + InsertFloppyDisks(SLOT6, g_cmdLine.szImageName_drive[SLOT6], g_cmdLine.bBoot); + g_cmdLine.szImageName_drive[SLOT6][DRIVE_1] = g_cmdLine.szImageName_drive[SLOT6][DRIVE_2] = NULL; // Don't insert on a restart + + InsertHardDisks(g_cmdLine.szImageName_harddisk, g_cmdLine.bBoot); + g_cmdLine.szImageName_harddisk[HARDDISK_1] = g_cmdLine.szImageName_harddisk[HARDDISK_2] = NULL; // Don't insert on a restart + + if (g_cmdLine.bSlotEmpty[7]) + { + HD_SetEnabled(false); // Disable HDD controller, but don't persist this to Registry/conf.ini (consistent with other '-sn empty' cmds) + 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(); + + 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(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license + } + + if (g_bCapturePrintScreenKey) + { + RegisterHotKeys(); // needs valid g_hFrameWindow + LogFileOutput("Main: RegisterHotKeys()\n"); + } + + if (g_bHookSystemKey) + { + if (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 call Disk2Card's Reset(): + GetCardMgr().GetDisk2CardMgr().Reset(true); // Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor + LogFileOutput("Main: DiskReset()\n"); + HD_Reset(); // GH#515 + LogFileOutput("Main: HDDReset()\n"); + + if (!g_bSysClkOK) + { + MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("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()); + MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); + g_cmdLine.bShutdown = true; + } + + tfe_init(); + LogFileOutput("Main: tfe_init()\n"); + + if (g_cmdLine.szSnapshotName) + { + std::string strPathname(g_cmdLine.szSnapshotName); + int nIdx = strPathname.find_last_of('\\'); + 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_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) + { + Video_RedrawAndTakeScreenShot(g_cmdLine.szScreenshotFilename); + g_cmdLine.bShutdown = true; + } + + if (g_cmdLine.bShutdown) + { + PostMessage(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.bSetFullScreen) + { + if (g_cmdLine.bestWidth && g_cmdLine.bestHeight) + { + DEVMODE devMode; + memset(&devMode, 0, sizeof(devMode)); + devMode.dmSize = sizeof(devMode); + devMode.dmPelsWidth = g_cmdLine.bestWidth; + devMode.dmPelsHeight = g_cmdLine.bestHeight; + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + DWORD dwFlags = 0; + LONG res = ChangeDisplaySettings(&devMode, dwFlags); + if (res == 0) + g_cmdLine.bChangedDisplayResolution = true; + } + + PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); + g_cmdLine.bSetFullScreen = false; + } + + if (g_cmdLine.bBoot) + { + PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); + g_cmdLine.bBoot = false; + } + } +} + +static void Shutdown(void) +{ + if (g_cmdLine.bChangedDisplayResolution) + ChangeDisplaySettings(NULL, 0); // restore default + + // Release COM + DDUninit(); + SysClk_UninitTimer(); + LogFileOutput("Exit: SysClk_UninitTimer()\n"); + + CoUninitialize(); + LogFileOutput("Exit: CoUninitialize()\n"); + + tfe_shutdown(); + LogFileOutput("Exit: tfe_shutdown()\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) + UnplugHardDiskControllerCard(); +} diff --git a/source/Windows/AppleWin.h b/source/Windows/AppleWin.h new file mode 100644 index 00000000..cc05e0e9 --- /dev/null +++ b/source/Windows/AppleWin.h @@ -0,0 +1,14 @@ +#pragma once + +void SingleStep(bool bReinit); + +//=========================================== + +// Win32 +extern HINSTANCE g_hInstance; + +bool GetLoadedSaveStateFlag(void); +void SetLoadedSaveStateFlag(const bool bFlag); +bool GetHookAltGrControl(void); + +extern bool g_bRestartFullScreen; diff --git a/source/Windows/WinFrame.cpp b/source/Windows/WinFrame.cpp index 5911eb59..de26836d 100644 --- a/source/Windows/WinFrame.cpp +++ b/source/Windows/WinFrame.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Windows/WinFrame.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" #include "CardManager.h" #include "CPU.h" #include "Disk.h" diff --git a/source/Windows/WinVideo.cpp b/source/Windows/WinVideo.cpp index 13b01114..9fbffa91 100644 --- a/source/Windows/WinVideo.cpp +++ b/source/Windows/WinVideo.cpp @@ -30,8 +30,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Windows/WinVideo.h" #include "Windows/WinFrame.h" -#include "AppleWin.h" +#include "Windows/AppleWin.h" #include "Video.h" +#include "Core.h" #include "CPU.h" #include "Joystick.h" #include "Frame.h" diff --git a/source/Z80VICE/z80.cpp b/source/Z80VICE/z80.cpp index 75989b92..f3a6fd06 100644 --- a/source/Z80VICE/z80.cpp +++ b/source/Z80VICE/z80.cpp @@ -26,7 +26,6 @@ #include "../StdAfx.h" -#include "../AppleWin.h" #include "../CPU.h" #include "../Memory.h" #include "../YamlHelper.h" diff --git a/source/z80emu.cpp b/source/z80emu.cpp index d177bf19..c3f77486 100644 --- a/source/z80emu.cpp +++ b/source/z80emu.cpp @@ -16,7 +16,6 @@ #include "StdAfx.h" #include "z80emu.h" -#include "AppleWin.h" #include "CPU.h" #include "Memory.h" diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp index acc3c55b..05289c27 100644 --- a/test/TestCPU6502/TestCPU6502.cpp +++ b/test/TestCPU6502/TestCPU6502.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" -#include "../../source/AppleWin.h" +#include "../../source/Windows/AppleWin.h" #include "../../source/CPU.h" #include "../../source/Memory.h" #include "../../source/SynchronousEventManager.h"