From a9a95fa3691e5adab1a7f41894a9c8dcb1c34183 Mon Sep 17 00:00:00 2001 From: ejaquay Date: Wed, 21 Jan 2026 11:30:09 -0500 Subject: [PATCH 1/4] refactor dialogops --- libcommon/include/vcc/bus/basic_cartridge.h | 1 - libcommon/include/vcc/bus/cartridge.h | 7 +- libcommon/include/vcc/bus/cartridge_loader.h | 11 +- libcommon/include/vcc/bus/cpak_cartridge.h | 12 +- libcommon/include/vcc/util/DialogOps.h | 150 ++++++++++++++----- libcommon/include/vcc/util/fileutil.h | 30 ++-- libcommon/src/bus/cartridge_loader.cpp | 12 +- libcommon/src/bus/cpak_cartridge.cpp | 6 +- libcommon/src/util/DialogOps.cpp | 128 +++------------- mpi/multipak_cartridge.cpp | 37 ++--- pakinterface.cpp | 14 +- 11 files changed, 198 insertions(+), 210 deletions(-) diff --git a/libcommon/include/vcc/bus/basic_cartridge.h b/libcommon/include/vcc/bus/basic_cartridge.h index 89cd296a..e6d90932 100644 --- a/libcommon/include/vcc/bus/basic_cartridge.h +++ b/libcommon/include/vcc/bus/basic_cartridge.h @@ -18,7 +18,6 @@ #pragma once #include -//TODO: Stomp this bad boy out. It has no purpose namespace VCC::Core { diff --git a/libcommon/include/vcc/bus/cartridge.h b/libcommon/include/vcc/bus/cartridge.h index df9fa829..da92f934 100644 --- a/libcommon/include/vcc/bus/cartridge.h +++ b/libcommon/include/vcc/bus/cartridge.h @@ -19,21 +19,19 @@ #include // defines LIBCOMMON_EXPORT if libcommon is a DLL #include - namespace VCC::Core { struct LIBCOMMON_EXPORT cartridge { public: - + // In Chet's workd strings get a typedef because that keeps things opaque using name_type = std::string; using catalog_id_type = std::string; using description_type = std::string; - public: - + // lock cartridge objects down by deleting move constructers cartridge() = default; cartridge(const cartridge&) = delete; cartridge(cartridge&&) = delete; @@ -46,7 +44,6 @@ namespace VCC::Core virtual void start() = 0; virtual void stop() = 0; - virtual void reset() = 0; virtual void process_horizontal_sync() = 0; virtual void write_port(unsigned char port_id, unsigned char value) = 0; diff --git a/libcommon/include/vcc/bus/cartridge_loader.h b/libcommon/include/vcc/bus/cartridge_loader.h index 89515a2e..e7ce02ae 100644 --- a/libcommon/include/vcc/bus/cartridge_loader.h +++ b/libcommon/include/vcc/bus/cartridge_loader.h @@ -61,7 +61,6 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_file_type determine_cartridge_type(const std::string& filename); - // TODO: Eliminate the redundant overloads of loader result LIBCOMMON_EXPORT cartridge_loader_result load_rom_cartridge( const std::string& filename, std::unique_ptr cartridge_context); @@ -69,18 +68,18 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_loader_result load_cpak_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks); LIBCOMMON_EXPORT cartridge_loader_result load_cartridge( const std::string& filename, // Cartridge filename - std::unique_ptr cartridge_context, // Yet another cartridge context - void* const host_context, // Even more context + std::unique_ptr cartridge_context, // Loader context + void* const pakContainer, // Pak container object const std::string& iniPath, // Path of ini file - HWND hVccWnd, // handle to main VCC window proc - const cpak_callbacks& cpak_callbacks); // Callbacks AKA context + HWND hVccWnd, // handle to main window + const cpak_callbacks& cpak_callbacks); // Callbacks // Return load error string per cartridge load status LIBCOMMON_EXPORT std::string cartridge_load_error_string( diff --git a/libcommon/include/vcc/bus/cpak_cartridge.h b/libcommon/include/vcc/bus/cpak_cartridge.h index 1244787c..24ce1205 100644 --- a/libcommon/include/vcc/bus/cpak_cartridge.h +++ b/libcommon/include/vcc/bus/cpak_cartridge.h @@ -35,11 +35,11 @@ namespace VCC::Core public: LIBCOMMON_EXPORT cpak_cartridge( - HMODULE module_handle, // Cartridge filename - void* const host_context, // Yet another cartridge context - path_type configuration_path, // Path of ini file - HWND hVccWnd, // Handle to main VCC window proc - const cpak_callbacks& cpak_callbacks); // Callbacks AKA context + HMODULE module_handle, // Cartridge filename + void* const pakContainer, // pointer to container object + path_type configuration_path, // Path of ini file + HWND hVccWnd, // Handle to main VCC window proc + const cpak_callbacks& cpak_callbacks); // Callbacks LIBCOMMON_EXPORT name_type name() const override; LIBCOMMON_EXPORT catalog_id_type catalog_id() const override; @@ -61,7 +61,7 @@ namespace VCC::Core private: const HMODULE handle_; - void* const host_context_; + void* const pakContainer_; const HWND hVccWnd_; const path_type configuration_path_; const cpak_callbacks cpak_callbacks_; diff --git a/libcommon/include/vcc/util/DialogOps.h b/libcommon/include/vcc/util/DialogOps.h index fe8ca942..1b2b4eee 100644 --- a/libcommon/include/vcc/util/DialogOps.h +++ b/libcommon/include/vcc/util/DialogOps.h @@ -17,6 +17,8 @@ //////////////////////////////////////////////////////////////////////////////// #pragma once #include // defines LIBCOMMON_EXPORT if libcommon is a DLL +#include +#include #include //------------------------------------------------------------------------------------------- @@ -33,22 +35,6 @@ LIBCOMMON_EXPORT void CenterDialog(HWND hDlg); // otherwise the open dialog is shown. If "Owner" is NULL GetActiveWindow() is used. // The selected filename is placed in "Path" // -// setpath() sets "Path" before calling show(). -// -// setDefExt(), setInitialDir(), setFilter(), setFlags(), and setTitle() set the -// elements in the OPENFILENAME structure that is used by get save/open file() -// -// path() returns a pointer to Path. -// getpath gets a copy of "Path". -// getdir() returns a copy of the directory portion of "Path" -// getupath() gets a copy of "Path" with all '\' chars replaced by '/' -// -// upath_ is a copy of path_ with backslashes converted to slashes -// -// There is an effort to standardize VCC using slashes as directory seperators -// but GetSaveFileName(&ofn_) and GetOpenFileName are older windows functions -// that do not play well with slashes so there is a bit of converting in and out; -// //------------------------------------------------------------------------------------------- #include #include @@ -57,31 +43,123 @@ class LIBCOMMON_EXPORT FileDialog { public: - FileDialog(); + FileDialog() { + ZeroMemory(&ofn_, sizeof(ofn_)); + ofn_.lStructSize = sizeof(ofn_); + flags_ = OFN_HIDEREADONLY; + } + + void init() { + ZeroMemory(&ofn_, sizeof(ofn_)); + ofn_.lStructSize = sizeof(ofn_); + flags_ = OFN_HIDEREADONLY; + } bool show(BOOL Save = FALSE, HWND Owner = nullptr); - void setpath(const char * Path); - void setDefExt(const char * DefExt); - void setInitialDir(const char * InitialDir); - void setFilter(const char * Filter); - void setFlags(unsigned int Flags); - void setTitle(const char * Title); - void getdir(char * Dir, int maxsize = MAX_PATH) const; - void getpath(char * Path, int maxsize = MAX_PATH) const; - void getupath(char * Path, int maxsize = MAX_PATH) const; - void gettype(char * Type, int maxsize = 4) const; - std::string getdir(); - std::string gettype(); - std::string getpath(); - - const char *path() const; - const char *upath() const; + + void setDefExt(const char * DefExt) + { + sDefext_.assign(DefExt ? DefExt : ""); + } + + void setInitialDir(const char * InitialDir) + { + sInitDir_.assign(InitialDir ? InitialDir : ""); + } + + //Set null terminated Filter items + void setFilter(const char* Filter) + { + sFilter_.clear(); + if (!Filter) return; + const char* p = Filter; + while (*p) p += std::strlen(p) + 1; + sFilter_.assign(Filter, p + 1 - Filter); + } + + void setFlags(unsigned int Flags) + { + flags_ = Flags | OFN_HIDEREADONLY; + } + + void setTitle(const char * Title) + { + sTitle_.assign(Title ? Title : ""); + } + + void setpath(const char * File) + { + sFile_.assign(File ? File : ""); + } + + // Return selected file + std::string getpath() const + { + return sFile_; + } + + // Return selected directory + std::string getdir() const + { + return VCC::Util::GetDirectoryPart(sFile_); + } + + // Return selected filetype + std::string gettype() const + { + std::string s = VCC::Util::GetFileNamePart(sFile_); + size_t pos = s.rfind('.'); + if (pos == std::string::npos || pos == s.size()-1) return {}; + return s.substr(pos+1); + } + + // Get a copy of the selected file path + void getpath(char * PathCopy, int maxsize=MAX_PATH) const + { + if (PathCopy == nullptr) return; + strncpy(PathCopy,sFile_.c_str(),maxsize); + } + + // Copy of the selected file path + void getupath(char * PathCopy, int maxsize=MAX_PATH) const + { + if (PathCopy == nullptr) return; + strncpy(PathCopy,sFile_.c_str(),maxsize); + } + + // copy the directory to c string + void getdir(char * Dir, int maxsize=MAX_PATH) const + { + if (Dir == nullptr) return; + VCC::Util::copy_to_char(getdir(),Dir,maxsize); + } + + // copy the file type to c string + void gettype(char * Type, int maxsize=16) const + { + if (Type == nullptr) return; + VCC::Util::copy_to_char(gettype(),Type,maxsize); + } + + // Get a pointer to the selected file path + const char *path() const + { + return sFile_.c_str(); + } + + const char *upath() const + { + return sFile_.c_str(); + } private: OPENFILENAME ofn_; - char path_[MAX_PATH] = {}; - char upath_[MAX_PATH] = {}; - char initialdir_[MAX_PATH] = {}; + std::string sFile_ {}; + std::string sInitDir_ {}; + std::string sTitle_ {}; + std::string sFilter_ {}; + std::string sDefext_ {}; + DWORD flags_; }; diff --git a/libcommon/include/vcc/util/fileutil.h b/libcommon/include/vcc/util/fileutil.h index 5ae1c1fc..c4bb74f4 100644 --- a/libcommon/include/vcc/util/fileutil.h +++ b/libcommon/include/vcc/util/fileutil.h @@ -161,23 +161,29 @@ namespace VCC::Util { // TODO: In line functions that should go elsewhere //------------------------------------------------------------------------ - // Return string with case conversion + // Return string with case conversion + inline std::string to_lower(std::string s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::tolower(c); }); - return s; - } + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + return s; + } inline std::string to_upper(std::string s) { std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::toupper(c); }); + [](unsigned char c) { + return static_cast(std::toupper(c)); + }); return s; } - // Convert case of string inplace inline void make_lower(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::tolower(c); }); + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::tolower(c)); + }); } inline void make_lower(char* s) { @@ -187,8 +193,10 @@ namespace VCC::Util { } inline void make_upper(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::toupper(c); }); + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::toupper(c)); + }); } inline void make_upper(char* s) { diff --git a/libcommon/src/bus/cartridge_loader.cpp b/libcommon/src/bus/cartridge_loader.cpp index 6370dedc..07e5e01d 100644 --- a/libcommon/src/bus/cartridge_loader.cpp +++ b/libcommon/src/bus/cartridge_loader.cpp @@ -117,7 +117,7 @@ namespace VCC::Core cartridge_loader_result load_cpak_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks) @@ -142,7 +142,7 @@ namespace VCC::Core { details.cartridge = std::make_unique( details.handle.get(), - host_context, + pakContainer, iniPath, hVccWnd, cpak_callbacks); @@ -156,7 +156,7 @@ namespace VCC::Core // Load a cartridge; either a ROM image or a pak dll. Load cartridge is called // by both mpi/multipak_cartridge.cpp and pakinterface.cpp. cartridge_context is defined - // in libcommon/include/vcc/bus/cartridge_context.h. host_context is a generic + // in libcommon/include/vcc/bus/cartridge_context.h. pakContainer is a generic // pointer explicitly cast to multipak_cartridge in mpi/multipak_cartridge.cpp. // mutlipak_cartridge refers specifically to a cart loaded by the multipak. // cpak_callbacks is used by all hardware paks and is defined in @@ -165,7 +165,7 @@ namespace VCC::Core cartridge_loader_result load_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks) @@ -184,10 +184,10 @@ namespace VCC::Core return VCC::Core::load_cpak_cartridge( filename, move(cartridge_context), - host_context, + pakContainer, iniPath, hVccWnd, - cpak_callbacks); // Callbacks hidden in here + cpak_callbacks); // Callbacks in here } } diff --git a/libcommon/src/bus/cpak_cartridge.cpp b/libcommon/src/bus/cpak_cartridge.cpp index cb23a0aa..12f04327 100644 --- a/libcommon/src/bus/cpak_cartridge.cpp +++ b/libcommon/src/bus/cpak_cartridge.cpp @@ -80,13 +80,13 @@ namespace VCC::Core cpak_cartridge::cpak_cartridge( HMODULE module_handle, - void* const host_context, + void* const pakContainer, path_type configuration_path, const HWND hVccWnd, const cpak_callbacks& cpak_callbacks) : handle_(module_handle), - host_context_(host_context), + pakContainer_(pakContainer), configuration_path_(move(configuration_path)), hVccWnd_(hVccWnd), cpak_callbacks_(cpak_callbacks), @@ -127,7 +127,7 @@ namespace VCC::Core void cpak_cartridge::start() { - initialize_(host_context_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); + initialize_(pakContainer_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); } void cpak_cartridge::stop() diff --git a/libcommon/src/util/DialogOps.cpp b/libcommon/src/util/DialogOps.cpp index 9649591a..96510885 100644 --- a/libcommon/src/util/DialogOps.cpp +++ b/libcommon/src/util/DialogOps.cpp @@ -20,7 +20,6 @@ #include #include #include -//#include //------------------------------------------------------------------------------------------- // FileDialog class shows a dialog for user to select a file for open or save. @@ -30,19 +29,23 @@ // do not play well with slashes so there is a bit of converting in and out; // // "path" refers to reverse slash path -// "upath" refers to forward slash path // //------------------------------------------------------------------------------------------- -// FileDialog constructor initializes open file name structure. -FileDialog::FileDialog() { - ZeroMemory(&ofn_, sizeof(ofn_)); - ofn_.lStructSize = sizeof(ofn_); - ofn_.Flags = OFN_HIDEREADONLY; -} - // FileDialog::show calls GetOpenFileName() or GetSaveFileName() bool FileDialog::show(BOOL Save, HWND Owner) { + + char file[MAX_PATH]; + ::VCC::Util::copy_to_char(sFile_,file,sizeof(file)); + ::VCC::Util::RevDirSlashes(file); + ofn_.nMaxFile = sizeof(file); + ofn_.lpstrFile = file; + + char idir[MAX_PATH]; + ::VCC::Util::copy_to_char(sInitDir_,idir,sizeof(idir)); + ::VCC::Util::RevDirSlashes(idir); + ofn_.lpstrInitialDir = idir; + // instance is that of the current module ofn_.hInstance = GetModuleHandle(nullptr); @@ -53,8 +56,10 @@ bool FileDialog::show(BOOL Save, HWND Owner) { ofn_.hwndOwner = GetActiveWindow(); } - ofn_.nMaxFile = sizeof(path_); - ofn_.lpstrFile = path_; + ofn_.lpstrDefExt = sDefext_.c_str(); + ofn_.lpstrFilter = sFilter_.c_str(); + ofn_.lpstrTitle = sTitle_.c_str(); + ofn_.Flags |= flags_; // Call Save or Open per boolean int rc; @@ -64,101 +69,14 @@ bool FileDialog::show(BOOL Save, HWND Owner) { rc = GetOpenFileName(&ofn_) ; } - // upath_ is the forward slash version - if (rc == 1) { - strncpy (upath_,path_,MAX_PATH); - VCC::Util::FixDirSlashes(upath_); - } - - return ((rc == 1) && (*path_ != '\0')); -} - -void FileDialog::setDefExt(const char * DefExt) { - ofn_.lpstrDefExt = DefExt; -} - -void FileDialog::setInitialDir(const char * InitialDir) { - if (InitialDir == nullptr) return; - strncpy(initialdir_,InitialDir,MAX_PATH); - VCC::Util::RevDirSlashes(initialdir_); - ofn_.lpstrInitialDir = initialdir_; -} - -void FileDialog::setFilter(const char * Filter) { - ofn_.lpstrFilter = Filter; -} - -void FileDialog::setFlags(unsigned int Flags) { - ofn_.Flags |= Flags; -} - -void FileDialog::setTitle(const char * Title) { - ofn_.lpstrTitle = Title; -} - -// Overwrite what is currently in path_ -void FileDialog::setpath(const char * NewPath) { - if (NewPath == nullptr) return; - strncpy(path_,NewPath,MAX_PATH); - VCC::Util::RevDirSlashes(path_); - strncpy(upath_,NewPath,MAX_PATH); - VCC::Util::FixDirSlashes(upath_); -} - -// Get a copy of the selected file path -void FileDialog::getpath(char * PathCopy, int maxsize) const { - if (PathCopy == nullptr) return; - strncpy(PathCopy,path_,maxsize); -} - -// Get a copy of the selected file path with slash delimiters -void FileDialog::getupath(char * PathCopy, int maxsize) const { - if (PathCopy == nullptr) return; - strncpy(PathCopy,upath_,maxsize); -} - -// Get a pointer to the selected file path -const char *FileDialog::path() const -{ - return path_; -} -const char *FileDialog::upath() const -{ - return upath_; -} - -// FileDialog::getdir() returns the directory portion of the file path -void FileDialog::getdir(char * Dir, int maxsize) const { - if (Dir == nullptr) return; - std::string s = VCC::Util::GetDirectoryPart(path_); - VCC::Util::copy_to_char(s,Dir,maxsize); -} + // Copy file selected back + if ((rc == 1) && (*file != '\0')) { + sFile_.assign(file ? file : ""); + VCC::Util::FixDirSlashes(sFile_); + return true; + }; -// FileDialog::gettype() returns the file type -void FileDialog::gettype(char * Type, int maxsize) const { - if (Type == nullptr) return; - if (maxsize < 1) return; - *Type = '\0'; - std::string s = VCC::Util::GetFileNamePart(path_); - size_t pos = s.rfind('.'); - if (pos == std::string::npos || pos == s.size()-1) return; - VCC::Util::copy_to_char(s.substr(pos+1),Type,maxsize); -} - -// String overloads for path_ and path_ components -std::string FileDialog::getpath() { - return path_; -} -std::string FileDialog::getdir() { - if (path_ == nullptr) return ""; - std::filesystem::path p(path_); - return p.parent_path().string(); - -} -std::string FileDialog::gettype() { - if (path_ == nullptr) return ""; - std::filesystem::path p(path_); - return p.extension().string(); + return false; } //------------------------------------------------------------ diff --git a/mpi/multipak_cartridge.cpp b/mpi/multipak_cartridge.cpp index 84294dc3..35ee09fe 100644 --- a/mpi/multipak_cartridge.cpp +++ b/mpi/multipak_cartridge.cpp @@ -26,31 +26,26 @@ namespace { - // Callback trampolines - // host_context is the opaque callback_context provided for this cartridge instance. - // In multipak this is always a multipak_cartridge*, allowing the trampoline to - // bounce the operation to the correct slot without exposing host internals. + // pakContainer is a pointer to the cartridge object. It is passed to cartridge DLL's + // and returned with callbacks allowing the trampoline to bounce the operation + // to the correct slot without exposing host internals + // TODO: This could have been done with just a slot number! template - void assert_cartridge_line_on_slot(void* host_context, bool line_state) + void assert_cartridge_line_on_slot(void* pakContainer, bool line_state) { - static_cast(host_context)->assert_cartridge_line( + static_cast(pakContainer)->assert_cartridge_line( SlotIndex_, line_state); } template - void append_menu_item_on_slot(void* host_context, const char* text, int id, MenuItemType type) + void append_menu_item_on_slot(void* pakContainer, const char* text, int id, MenuItemType type) { - static_cast(host_context)->append_menu_item( + static_cast(pakContainer)->append_menu_item( SlotIndex_, { text, static_cast(id), type }); } // Per-slot callback table. - // Each entry provides the host-side trampoline functions for that slot, - // allowing cartridges to call back into multipak using a uniform API - // while the trampolines route the request to the correct slot. - // Multipak uses two slot specific callbacks, the rest are just passed from vcc. - // TODO: This could have been done with just a slot number! struct cartridge_slot_callbacks { PakAssertCartridgeLineHostCallback set_cartridge_line; @@ -164,8 +159,8 @@ void multipak_cartridge::write_port(unsigned char port_id, unsigned char value) // slot_select_port_id is 0x7f if (port_id == slot_select_port_id) { - // Bits 1-0 SCS slot (FDC) - // Bits 5-4 CTS slot (ROM) + // Bits 1-0 SCS slot + // Bits 5-4 CTS slot cached_scs_slot_ = value & 3; cached_cts_slot_ = (value >> 4) & 3; slot_register_ = value; @@ -322,6 +317,7 @@ void multipak_cartridge::eject_cartridge(slot_id_type slot) SendMessage(gVccWnd,WM_COMMAND,(WPARAM) ID_FILE_RESET,(LPARAM) 0); } +// create cartridge object and load cart DLL multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( slot_id_type slot, const path_type& filename) { @@ -334,23 +330,20 @@ multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( }; DLOG_C("%3d %p %p %p %p %p\n",slot,callbacks); - auto* multipakHost = this; + auto* pakContainer = this; - // callback_context is a host-owned opaque per-cartridge state. Passed to cartridges - // at initialization and returned on every callback so the host can route and manage a - // specific cartridge instance. MPI currently uses it to know what slot a cart is in. + // ctx is passed to the loader but not to cartridge DLL's auto ctx = std::make_unique( slot, *context_, - *multipakHost); - + *pakContainer); DLOG_C("load cart %d %s\n",slot,filename); auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(ctx), - multipakHost, + pakContainer, context_->configuration_path(), gVccWnd, callbacks); diff --git a/pakinterface.cpp b/pakinterface.cpp index 2c0500a2..6dc08a14 100644 --- a/pakinterface.cpp +++ b/pakinterface.cpp @@ -287,14 +287,7 @@ cartridge_loader_status PakLoadCartridge(const char* filename) // Insert Module returns 0 on success static cartridge_loader_status load_any_cartridge(const char *filename, const char* iniPath) { - // callback_context is a host-owned opaque per-cartridge state. Passed to the cartridge - // at initialization and returned on every callback so the host can route and manage a - // specific cartridge instance. Currently for pakinterface it is empty, but MPI uses it. - - // TODO:: Consider using a slot number instead. slot0 for this, slot1-slot4 for MMI - // That way all loaded cart context can reside in a simple vector with no reliance - // on cart trampolines to maintain context. With slot_num in the callbacks MPI will - // not have intercept to adjust menu_id's and forwarding the callback to main. + // vccContext is passed to the loader but not to the cart DLL auto vccContext=std::make_unique(); cpak_callbacks callbacks { @@ -308,7 +301,7 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(vccContext), - nullptr, // No host context for the main app + nullptr, // pakContainer goes here iniPath, EmuState.WindowHandle, callbacks); @@ -318,6 +311,7 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch return loadedCartridge.load_result; } + // unload active cartridge UnloadDll(); VCC::Util::section_locker lock(gPakMutex); @@ -326,6 +320,8 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch gActiveCartrige = move(loadedCartridge.cartridge); gActiveModule = move(loadedCartridge.handle); BeginCartMenu(); + + // initialize the cartridge gActiveCartrige->start(); // Reset if enabled. TODO: Send DoHardReset message instead From 75ff97a615f73b2fef57cc66b456ec22d4d5c9ea Mon Sep 17 00:00:00 2001 From: ejaquay Date: Fri, 30 Jan 2026 00:31:32 -0500 Subject: [PATCH 2/4] Add Interface design document --- libcommon/src/bus/CartridgeInterface.txt | 301 +++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 libcommon/src/bus/CartridgeInterface.txt diff --git a/libcommon/src/bus/CartridgeInterface.txt b/libcommon/src/bus/CartridgeInterface.txt new file mode 100644 index 00000000..679459e2 --- /dev/null +++ b/libcommon/src/bus/CartridgeInterface.txt @@ -0,0 +1,301 @@ + +This attempts to describe the cartridge interface design for VCC + +--- + +# VCC Cartridge Types + +VCC emulates the physical cartridges that could be plugged into the side expansion slot of a CoCo 3 or into a MultiPak Interface. VCC supports three main categories of cartridges: + +--- + +## 1. ROM Cartridges + +ROM cartridges contain only read-only memory and the minimal hardware needed to expose that memory to the CoCo. + +**Key characteristics:** + +- Typically contain 6809 or 6309 executable code. +- The CoCo reads data directly from mapped ROM addresses. +- Some cartridges support bank switching by writing to I/O ports. +- In VCC, all ROM banking logic is implemented inside the emulator itself. + +**Implications for VCC:** + +- ROM cartridges require no host-side code. +- They are stored as simple binary files. +- Some ROM files include headers or signatures to indicate special mapping or banking behavior. +- Most common ROM cartridges were 16 KB or smaller and mapped at `0xC000` in ROM mode. + +--- + +## 2. Hardware Cartridges + +Hardware cartridges contain actual devices, such as: + +- Disk controllers +- Sound synthesizers +- RS-232 interfaces +- Additional microprocessors +- Often, onboard ROM + +These cartridges require host-side x86 code to emulate their hardware behavior. + +**In VCC:** + +- Hardware cartridges are implemented as **Windows DLLs**. +- VCC identifies them by checking for the `MZ` signature at the start of the file. +- Hardware DLL's must export the initCart call to be valid +- ROM data for these cartridges is usually stored separately, though this is not required. +- Some hardware cartridges can load multiple ROMs and switch between them under program control. +- The DLL is responsible for loading and managing these ROMs. +- The CoCo communicates with the emulated hardware by reading and writing specific I/O ports. +- Hardware cartridges may generate interrupts or output audio through a dedicated sound channel. +- Hardware cartridges cannot load other hardware cartridges. + +--- + +## 3. MultiPak Cartridges + +MultiPak cartridges act as hosts for other hardware cartridges. + +**Capabilities:** + +- MultiPak Cartridge DLL must export the initMPI call to be valid +- Provide multiple cartridge slots. +- Contains no ROM of it's own +- Allow slot selection through UI controls or programmatically. + +**VCC support:** + +- VCC currently emulates the original Radio Shack MultiPak Interface. +- Multipak can only be inserted Coco slide slot, not into another multipak. +- Third-party MultiPak-style devices also exist, including: + - Two-slot versions + - Hobbyist designs supporting up to eight slots + +--- + +# Cartridge Loader: Cartridge Type Identification Logic + +The cartridge loader determines the cartridge type using the following sequence: + +1. **Check if the file can be read** + - If it cannot be read, the cartridge is **not loadable**. + +2. **Check if the file is a DLL** + - If it is *not* a DLL, the cartridge is a **ROM Cartridge**. + +3. **Check if the DLL exports `InitCart`** + - If it does *not*, the cartridge is **not loadable**. + +4. **Check if the DLL exports PakGetCapabilities** + - If it does not, the cartridge is CART_TYPE_GENERIC + +5. Continue with loading and initialization + + +--- + +Cartridge Exports + + +DLL's can export any of the following calls + + Get cart type and capabilities (required) + Const cart_capabilities* PakGetCapabilities (void); + + Initiate pack (required) + PakInitialize (slot_context, settings_path, hVccWnd_, &callbacks); + + Terminate pack, prepare for DLL unload + PakTerminate () + + Get pack name + PakGetName (name, buf_size) + + Get pack ID + PakGetCatalogId (catalogId, buf_size) + + Get pack description + PakGetDescription (Description, buf_size) + + Reset the pack + PakReset () + + Horizontal sync occurred + PakProcessHorizontalSync () + + Get pack status line text + PakGetStatus (Status, buf_size) + + Write I/O port + PakWritePort (Port, data) + + Read I/O port + unsigned char PakReadPort (Port) + + Read ROM byten + unsigned char PakReadMemoryByte (Address) + + Sample audio line + unsigned short PakSampleAudio () + + A hardware pack menu item was clicked + PakMenuItemClicked (menu_item_id) + + +struct slot_context { + void* slot_context; // contains rounting table + int slot_number; // 0 = boot slot, 1..N = multipak slots + void* callbacks; // Call back table for this slot. +}; + +typedef enum { + CART_TYPE_GENERIC = 0; + CART_TYPE_MPI = 1; +} cart_type; + +typedef struct { + unit32_t version // for future expansion + cart_type type; + uint32_t flags; // future: has_audio, has_menu, etc +} cart_capabilities; + +Future exports can be added with out affecting existing cartridges as long as existing +exports are not changed. + +--- + +Callbacks + + void assert_cartridge_line(slot_context, bool line_state) = 0; + void assert_interrupt(slot_context, Interrupt interrupt, InterruptSource interrupt_source) = 0; + void write_memory_byte(slot_context, unsigned char value, unsigned short address) = 0; + unsigned char read_memory_byte(slot_context, unsigned short address) = 0; + void add_menu_item(slot_context, const char* menu_name, int menu_id, MenuItemType menu_type) = 0; + + slot_context is an opaque pointer to data MPI uses to route callbacks + + +It has recently been recognized that there are two classes of callbacks + +- Fast callbacks initiated by events in the CPU loop like asserting interrupts, cart +ines, or reading and writing memory to handle DMA requests. These must be syncronous +and return quickly to not affect emulator timing. Fast callbacks must use the already +in place callback mechanisms. Fast callbacks are determined by Coco's physical bus and +are not likely to change. + +- Slow callbacks initiated by UI like adding menu items or inserting cartridges in slots. +These can be asyncronous and can rely on exports to recieve replies. A perfect mechanism +for slow callbacks already exists for free - the main window message loop. A cartridge +can send a message to the main window and let VCC main dispatch it. Enhancements to +cartridge UI might require future changes or additions to these callbacks. + +In the current codebase the messaging mechanism is already being used for a callback. When +the MPI needs to initiate a hard VCC reset is does so by sending a message to WinMain. + +The add_menu_item callback is not tied to the CPU loop and qualifies as a slot callback. +This callback will be replaced by a Windows message. + +--- + +A new VCC Design philosophy for the MPI + +VCC and forks of VCC use run-time loading and unloading of dynamic libraries to simulate +the inserting and removing of Cartridges. + +A special "cartridge" it the Multipak MPI. On a physical Coco the MPI it is not actually +a cartridge. It is more accurately an extension of the bus. + +The pakinterface loads and unloads cartridges. So does the MPI. If both MPI and pakinterface +call cartridge DLLs directly there are now two modules, VCC and MPI, that need to know about +cartridge lifetimes, handles, exports, and inports. All loading and unloading of carts belongs +in one place and that place is the PakInterface part of VCC main. + +When slot management is moved to the Pakinterface the logic that controls the CTS and SCS and +the management of saved slot content settings must move too. The pakinterface must share this +information with the MPI DLL which becomes purely a user interface. + +Moving cartridge and slot management from the MPI to the Pakinterface would seem to require +extensive changes to the interface. This document attemps to explain how such a move can be +done with minimal changes. + +--- + +The dynamic cartridge menu system. + +When cartridges are loaded or unloaded the Cartridge menu must be changed to show items for +controlling the cartridges. Traditionally the Pakinterface generated the first menu item which +gives users control over which cartridge is plugged into the side of the coco. If that +cartridge is the MPI additional menu items are added, the first such item brings up a MPI +configuration dialog. That dialog shows the user what carts are in MPI slots, which cart +is selected at boot (CTS), a description of the cart in that slot, and controls allowing users +to modify these settings. After the MPI config menu item additional menu items are added +for cartridges currently in MPI slots. These menu items are added by carts as they are initialized. +Each cartridge, starting with the MPI, then carts in slots 4 through 1, are intialized. +When a cart is initialized to generates AddMenuitem callbacks for it's menu item. + +Using the cartridge initialization export to initiate the addition of menu items causes an +issue if a cart is removed or added after VCC has started up, specifically carts should not +be initialized a second time after loading. So add menu item messages are saved in a list and +the cart menu is cleared then the list is traversed to retore the menuitems after each change. + +--- + +To wrap up the pakinterface slot management concept: + +- The pakinterface maintains a list indexed by slot number of loaded cartridges. + +- Slots are numbered 0-4. Slot 0 is the Boot slot. Slots 1-4 only loaded if MPI is in the Boot slot. + +- The pakinterface maintains the cartridge menu and dynamic menu items + +- The pakInterface routes I/O to slots per CTS/SCS using existing capability / callcacks + +- The pakinterface saves slot content to settings. + +- Any change to current CTS triggers a reset. This is detected and effected by the pakinterface + +- Reset stops the CPU, unloads all cartridges, reloads the basic rom, reloads cartridges +per settings, and then restarts the CPU. + +- pakInterface sends MPI changes to CTS/SCS via a new MPI export + +- The opaque slot_context is renamed to slot_context and is made transparent. Some carts don't work right if +they are not a specific slot. They can use slot_context->slot_number to verify the slot they are in is valid. + +- on request pakInterface sends MPI active cart description via a new MPI export + +- on request pakInterface sends MPI slot contents + +- Then MPI should never call a cartridge DLL directly. It should always request actions through +messages to the pakInterface using the WinMain message loop. + +- The MPI saves the startup slot setting. Changing this causes no changes to running CPI + +- The MPI requests cartridge loads / unloads by sending messages to WinMain. + +- The MPI requests slot and cartridge information by sending messages to WinMain. + +- The MPI has new exports to recieve results from slot changes and cartridge information requests. + +- The MPI "Reset VCC" button sends a reset message to VCC main. + +- With the exception of add_menu_item() all other exports and callbacks remain the same. + +--- + +Implementation Plan + +1. Solidify methods for sending and interpreting messages from DLL's to WinMain message loop. +Use the VCC Reset message from MPI Config to prove the methods. + +2. Replace the AddCartMenu callback with a message and modify pakinterface to maintain the cartridge +dynamic menus. + +3. Move slot maintenance, cartridge loading, and cartidge calls from MPI to pakinterface. + +4. Cartridges can use slot_id from now transparent slot_context, if desired. + + From 4df4f5e68d3364e56f6df0c39a98d462bec1b55e Mon Sep 17 00:00:00 2001 From: ejaquay Date: Fri, 6 Feb 2026 21:22:26 -0500 Subject: [PATCH 3/4] Settings writes return bool result to indicate success --- config.cpp | 14 +-- libcommon/include/vcc/util/settings.h | 36 ++++--- libcommon/src/bus/CartridgeInterface.txt | 115 +++++++++-------------- libcommon/src/util/settings.cpp | 16 ++-- mpi/multipak_cartridge.cpp | 9 +- 5 files changed, 86 insertions(+), 104 deletions(-) diff --git a/config.cpp b/config.cpp index fadb1c0b..24b61038 100644 --- a/config.cpp +++ b/config.cpp @@ -120,7 +120,7 @@ struct STRConfig char PathtoExe[MAX_PATH] = { 0 }; char FloppyPath[MAX_PATH] = { 0 }; char CassPath[MAX_PATH] = { 0 }; - unsigned char ShowMousePointer = 0; + unsigned char ShowMousePointer = 0; unsigned char UseExtCocoRom = 0; char ExtRomFile[MAX_PATH] = { 0 }; unsigned char EnableOverclock = 0; @@ -218,11 +218,14 @@ void LoadConfig(SystemState *LCState) } else { ini = appData + "/Vcc.ini"; } + Util::copy_to_char(ini, gcIniFilePath, MAX_PATH); // Establish application path char AppName[MAX_LOADSTRING]=""; LoadString(nullptr, IDS_APP_TITLE,AppName, MAX_LOADSTRING); + + // Write release to ini file Setting().write("Version","Release",AppName); // Load settings @@ -236,18 +239,11 @@ void LoadConfig(SystemState *LCState) } //--------------------------------------------------------------- -// Fatal if this is called before valid gcIniFilePath is established +// This must not be called before valid gcIniFilePath is established //--------------------------------------------------------------- VCC::Util::settings& Setting() { if (!gpSettings) { - // Fatal if ini file can not be opened - if (!Util::ValidateRWFile(gcIniFilePath)) { - std::string s = "Can't open settings " - + std::string(gcIniFilePath); - MessageBox(EmuState.WindowHandle,s.c_str(),"Fatal",0); - exit(0); - } gpSettings = new Util::settings(gcIniFilePath); } return *gpSettings; diff --git a/libcommon/include/vcc/util/settings.h b/libcommon/include/vcc/util/settings.h index 70b977e7..ab1ae5e4 100644 --- a/libcommon/include/vcc/util/settings.h +++ b/libcommon/include/vcc/util/settings.h @@ -31,25 +31,25 @@ namespace VCC::Util LIBCOMMON_EXPORT explicit settings(path_type path); // write string value - LIBCOMMON_EXPORT void write + LIBCOMMON_EXPORT bool write (const std::string& section, const std::string& key, const std::string& value) const; // write int value - LIBCOMMON_EXPORT void write + LIBCOMMON_EXPORT bool write (const std::string& section, const std::string& key, int value) const; // write bool value - LIBCOMMON_EXPORT void write_bool + LIBCOMMON_EXPORT bool write_bool (const std::string& section, const std::string& key, bool value) const; // get char * value - LIBCOMMON_EXPORT void read + LIBCOMMON_EXPORT bool read (const std::string& section, const std::string& key, const std::string& default_value, @@ -69,22 +69,28 @@ namespace VCC::Util int default_value) const; // delete key - LIBCOMMON_EXPORT void delete_key + LIBCOMMON_EXPORT bool delete_key (const std::string& section, const std::string& key) const - { ::WritePrivateProfileString - (section.c_str(), key.c_str(), NULL, path_.c_str());} + { + return ::WritePrivateProfileString + (section.c_str(), key.c_str(), NULL, path_.c_str()); + } - // delete section - LIBCOMMON_EXPORT void delete_section + // delete section + LIBCOMMON_EXPORT bool delete_section (const std::string& section) const - { ::WritePrivateProfileString - (section.c_str(), NULL, NULL, path_.c_str());} + { + return ::WritePrivateProfileString + (section.c_str(), NULL, NULL, path_.c_str()); + } - // flush cache - LIBCOMMON_EXPORT void flush () const - { ::WritePrivateProfileString - (NULL, NULL, NULL, path_.c_str());} + // flush cache + LIBCOMMON_EXPORT bool flush () const + { + return ::WritePrivateProfileString + (NULL, NULL, NULL, path_.c_str()); + } private: const path_type path_; diff --git a/libcommon/src/bus/CartridgeInterface.txt b/libcommon/src/bus/CartridgeInterface.txt index 679459e2..16e7a895 100644 --- a/libcommon/src/bus/CartridgeInterface.txt +++ b/libcommon/src/bus/CartridgeInterface.txt @@ -5,13 +5,15 @@ This attempts to describe the cartridge interface design for VCC # VCC Cartridge Types -VCC emulates the physical cartridges that could be plugged into the side expansion slot of a CoCo 3 or into a MultiPak Interface. VCC supports three main categories of cartridges: +VCC emulates the physical cartridges that could be plugged into the side expansion slot of a CoCo 3 +or into a MultiPak Interface. VCC supports three main categories of cartridges: --- ## 1. ROM Cartridges -ROM cartridges contain only read-only memory and the minimal hardware needed to expose that memory to the CoCo. +ROM cartridges contain only read-only memory and the minimal hardware needed to expose that memory +to the CoCo 3. **Key characteristics:** @@ -55,13 +57,14 @@ These cartridges require host-side x86 code to emulate their hardware behavior. --- -## 3. MultiPak Cartridges +## 3. MultiPak Cartridge (MPI) -MultiPak cartridges act as hosts for other hardware cartridges. +MultiPak it not a true cartridge, it is a bus expansion that acts as hosts for other hardware +cartridges. **Capabilities:** -- MultiPak Cartridge DLL must export the initMPI call to be valid +- MultiPak Cartridge DLL must export the init MPI call to be valid - Provide multiple cartridge slots. - Contains no ROM of it's own - Allow slot selection through UI controls or programmatically. @@ -99,7 +102,6 @@ The cartridge loader determines the cartridge type using the following sequence: Cartridge Exports - DLL's can export any of the following calls Get cart type and capabilities (required) @@ -144,44 +146,20 @@ DLL's can export any of the following calls A hardware pack menu item was clicked PakMenuItemClicked (menu_item_id) - -struct slot_context { - void* slot_context; // contains rounting table - int slot_number; // 0 = boot slot, 1..N = multipak slots - void* callbacks; // Call back table for this slot. -}; - -typedef enum { - CART_TYPE_GENERIC = 0; - CART_TYPE_MPI = 1; -} cart_type; - -typedef struct { - unit32_t version // for future expansion - cart_type type; - uint32_t flags; // future: has_audio, has_menu, etc -} cart_capabilities; - -Future exports can be added with out affecting existing cartridges as long as existing -exports are not changed. - --- Callbacks - void assert_cartridge_line(slot_context, bool line_state) = 0; - void assert_interrupt(slot_context, Interrupt interrupt, InterruptSource interrupt_source) = 0; - void write_memory_byte(slot_context, unsigned char value, unsigned short address) = 0; - unsigned char read_memory_byte(slot_context, unsigned short address) = 0; - void add_menu_item(slot_context, const char* menu_name, int menu_id, MenuItemType menu_type) = 0; + void assert_cartridge_line(slot_context, bool line_state) = 0; + void assert_interrupt(slot_context, Interrupt interrupt, InterruptSource interrupt_source) = 0; + void write_memory_byte(slot_context, unsigned char value, unsigned short address) = 0; + unsigned char read_memory_byte(slot_context, unsigned short address) = 0; + void add_menu_item(slot_context, const char* menu_name, int menu_id, MenuItemType menu_type) = 0; - slot_context is an opaque pointer to data MPI uses to route callbacks - - -It has recently been recognized that there are two classes of callbacks +It has recently been recognized that there are two classes of callbacks: - Fast callbacks initiated by events in the CPU loop like asserting interrupts, cart -ines, or reading and writing memory to handle DMA requests. These must be syncronous +lines, or reading and writing memory to handle DMA requests. These must be syncronous and return quickly to not affect emulator timing. Fast callbacks must use the already in place callback mechanisms. Fast callbacks are determined by Coco's physical bus and are not likely to change. @@ -190,7 +168,7 @@ are not likely to change. These can be asyncronous and can rely on exports to recieve replies. A perfect mechanism for slow callbacks already exists for free - the main window message loop. A cartridge can send a message to the main window and let VCC main dispatch it. Enhancements to -cartridge UI might require future changes or additions to these callbacks. +cartridge UI that require future changes or additions should use these callbacks. In the current codebase the messaging mechanism is already being used for a callback. When the MPI needs to initiate a hard VCC reset is does so by sending a message to WinMain. @@ -200,12 +178,32 @@ This callback will be replaced by a Windows message. --- -A new VCC Design philosophy for the MPI +The dynamic cartridge menu system. + +When cartridges are loaded or unloaded the Cartridge menu must be changed to show items for +controlling the cartridges. Traditionally the Pakinterface generated the first menu item which +gives users control over which cartridge is plugged into the side of the coco. If that +cartridge is the MPI additional menu items are added, the first such item brings up a MPI +configuration dialog. That dialog shows the user what carts are in MPI slots, which cart +is selected at boot (CTS), a description of the cart in that slot, and controls allowing users +to modify these settings. After the MPI config menu item additional menu items are added +for cartridges currently in MPI slots. These menu items are added by carts as they are +initialized. Each cartridge, starting with the MPI, then carts in slots 4 through 1, are +intialized. When a cart is initialized to generates AddMenuitem callbacks for it's menu item. + +Using the cartridge initialization export to initiate the addition of menu items causes an +issue if a cart is removed or added after VCC has started up, specifically carts should not +be initialized a second time after loading. So add menu item messages are saved in a list and +the cart menu is cleared then the list is traversed to retore the menuitems after each change. + +--- + +New Design Philosophy For The MPI (Not yet implemented) VCC and forks of VCC use run-time loading and unloading of dynamic libraries to simulate the inserting and removing of Cartridges. -A special "cartridge" it the Multipak MPI. On a physical Coco the MPI it is not actually +A special "cartridge" is the Multipak MPI. On a physical Coco the MPI it is not actually a cartridge. It is more accurately an extension of the bus. The pakinterface loads and unloads cartridges. So does the MPI. If both MPI and pakinterface @@ -219,27 +217,7 @@ information with the MPI DLL which becomes purely a user interface. Moving cartridge and slot management from the MPI to the Pakinterface would seem to require extensive changes to the interface. This document attemps to explain how such a move can be -done with minimal changes. - ---- - -The dynamic cartridge menu system. - -When cartridges are loaded or unloaded the Cartridge menu must be changed to show items for -controlling the cartridges. Traditionally the Pakinterface generated the first menu item which -gives users control over which cartridge is plugged into the side of the coco. If that -cartridge is the MPI additional menu items are added, the first such item brings up a MPI -configuration dialog. That dialog shows the user what carts are in MPI slots, which cart -is selected at boot (CTS), a description of the cart in that slot, and controls allowing users -to modify these settings. After the MPI config menu item additional menu items are added -for cartridges currently in MPI slots. These menu items are added by carts as they are initialized. -Each cartridge, starting with the MPI, then carts in slots 4 through 1, are intialized. -When a cart is initialized to generates AddMenuitem callbacks for it's menu item. - -Using the cartridge initialization export to initiate the addition of menu items causes an -issue if a cart is removed or added after VCC has started up, specifically carts should not -be initialized a second time after loading. So add menu item messages are saved in a list and -the cart menu is cleared then the list is traversed to retore the menuitems after each change. +done with minimal risk. --- @@ -258,19 +236,20 @@ To wrap up the pakinterface slot management concept: - Any change to current CTS triggers a reset. This is detected and effected by the pakinterface - Reset stops the CPU, unloads all cartridges, reloads the basic rom, reloads cartridges -per settings, and then restarts the CPU. + per settings, and then restarts the CPU. - pakInterface sends MPI changes to CTS/SCS via a new MPI export -- The opaque slot_context is renamed to slot_context and is made transparent. Some carts don't work right if -they are not a specific slot. They can use slot_context->slot_number to verify the slot they are in is valid. +- The opaque slot_context is renamed to slot_context and is made transparent. Some carts don't + work right if they are not a specific slot. They can use slot_number to verify the slot they + are in is valid. - on request pakInterface sends MPI active cart description via a new MPI export - on request pakInterface sends MPI slot contents - Then MPI should never call a cartridge DLL directly. It should always request actions through -messages to the pakInterface using the WinMain message loop. + messages to the pakInterface using the WinMain message loop. - The MPI saves the startup slot setting. Changing this causes no changes to running CPI @@ -289,13 +268,13 @@ messages to the pakInterface using the WinMain message loop. Implementation Plan 1. Solidify methods for sending and interpreting messages from DLL's to WinMain message loop. -Use the VCC Reset message from MPI Config to prove the methods. + Use the VCC Reset message from MPI Config to prove the methods. 2. Replace the AddCartMenu callback with a message and modify pakinterface to maintain the cartridge -dynamic menus. + dynamic menus. 3. Move slot maintenance, cartridge loading, and cartidge calls from MPI to pakinterface. -4. Cartridges can use slot_id from now transparent slot_context, if desired. +4. Cartridges can use slot_id from transparent slot_context, if desired. diff --git a/libcommon/src/util/settings.cpp b/libcommon/src/util/settings.cpp index 95c643c8..bc2b6671 100644 --- a/libcommon/src/util/settings.cpp +++ b/libcommon/src/util/settings.cpp @@ -28,12 +28,12 @@ namespace VCC::Util {} // save string value - void settings::write( + bool settings::write( const std::string& section, const std::string& key, const std::string& value) const { - ::WritePrivateProfileString( + return ::WritePrivateProfileString( section.c_str(), key.c_str(), value.c_str(), @@ -41,12 +41,12 @@ namespace VCC::Util } // save int value - void settings::write + bool settings::write (const std::string& section, const std::string& key, int value) const { - ::WritePrivateProfileString( + return ::WritePrivateProfileString( section.c_str(), key.c_str(), std::to_string(value).c_str(), @@ -54,24 +54,24 @@ namespace VCC::Util } // save bool value - void settings::write_bool + bool settings::write_bool (const std::string& section, const std::string& key, bool value) const { int ival = value ? 1 : 0; - write(section, key, ival); + return write(section, key, ival); } // get char * value - void settings::read + bool settings::read (const std::string& section, const std::string& key, const std::string& default_value, char* buffer, size_t buffer_size) const { - ::GetPrivateProfileStringA( + return ::GetPrivateProfileStringA( section.c_str(), key.c_str(), default_value.c_str(), diff --git a/mpi/multipak_cartridge.cpp b/mpi/multipak_cartridge.cpp index 35ee09fe..aa2a309d 100644 --- a/mpi/multipak_cartridge.cpp +++ b/mpi/multipak_cartridge.cpp @@ -26,10 +26,6 @@ namespace { - // pakContainer is a pointer to the cartridge object. It is passed to cartridge DLL's - // and returned with callbacks allowing the trampoline to bounce the operation - // to the correct slot without exposing host internals - // TODO: This could have been done with just a slot number! template void assert_cartridge_line_on_slot(void* pakContainer, bool line_state) { @@ -330,6 +326,11 @@ multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( }; DLOG_C("%3d %p %p %p %p %p\n",slot,callbacks); + // pakContainer is a pointer to the multipak object. It is passed + // to cartridge DLL's and returned with callbacks to route them + // to the correct slot without exposing host internals. + // TODO: This could have been done with just a slot number! + auto* pakContainer = this; // ctx is passed to the loader but not to cartridge DLL's From a970c0e8c4aca2afdd3ab34498c27f1d158c983b Mon Sep 17 00:00:00 2001 From: ejaquay Date: Sat, 7 Feb 2026 20:28:26 -0500 Subject: [PATCH 4/4] Issue #547 FD502 allow long disk file names Buffer overflow building dynamic menu, increased buffer to MAX_PATH. Change names of some globals to avoid name conflicts. (no functional change) --- FD502/fd502.cpp | 60 ++-- FD502/wd1793.cpp | 343 ++++++++++++----------- libcommon/src/bus/CartridgeInterface.txt | 2 +- libcommon/src/util/FileOps.cpp | 2 +- 4 files changed, 204 insertions(+), 203 deletions(-) diff --git a/FD502/fd502.cpp b/FD502/fd502.cpp index dd7f529a..539a194d 100644 --- a/FD502/fd502.cpp +++ b/FD502/fd502.cpp @@ -50,7 +50,7 @@ constexpr auto EXTROMSIZE = 16384u; using namespace std; -extern DiskInfo Drive[5]; +extern DiskInfo gVirtualDrive[5]; static unsigned char ExternalRom[EXTROMSIZE]; static unsigned char DiskRom[EXTROMSIZE]; static unsigned char RGBDiskRom[EXTROMSIZE]; @@ -81,7 +81,7 @@ static HWND g_hConfDlg = nullptr; static HINSTANCE gModuleInstance; static unsigned long RealDisks=0; long CreateDisk (unsigned char); -static char TempFileName[MAX_PATH]=""; +static char gSelectedDiskFile[MAX_PATH]=""; unsigned char LoadExtRom( unsigned char, const char *); int BeckerEnabled=0; @@ -147,9 +147,9 @@ extern "C" becker_enable(0); #endif CloseCartDialog(g_hConfDlg); - for (unsigned char Drive = 0; Drive <= 3; Drive++) + for (unsigned char dnum = 0; dnum <= 3; dnum++) { - unmount_disk_image(Drive); + unmount_disk_image(dnum); } } @@ -267,7 +267,7 @@ LRESULT CALLBACK Config(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam* { static unsigned char temp=0,temp2=0; long ChipChoice[3]={IDC_EXTROM,IDC_TRSDOS,IDC_RGB}; - long VirtualDrive[2]={IDC_DISKA,IDC_DISKB}; + long gVirtualDrive[2]={IDC_DISKA,IDC_DISKB}; char VirtualNames[5][16]={"None","Drive 0","Drive 1","Drive 2","Drive 3"}; switch (message) @@ -297,7 +297,7 @@ LRESULT CALLBACK Config(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam* SendDlgItemMessage(hDlg,ChipChoice[temp],BM_SETCHECK,(temp==TempSelectRom),0); for (temp=0;temp<2;temp++) for (temp2=0;temp2<5;temp2++) - SendDlgItemMessage (hDlg,VirtualDrive[temp], CB_ADDSTRING, 0, (LPARAM) VirtualNames[temp2]); + SendDlgItemMessage (hDlg,gVirtualDrive[temp], CB_ADDSTRING, 0, (LPARAM) VirtualNames[temp2]); SendDlgItemMessage (hDlg, IDC_DISKA,CB_SETCURSEL,(WPARAM)PhysicalDriveA,(LPARAM)0); SendDlgItemMessage (hDlg, IDC_DISKB,CB_SETCURSEL,(WPARAM)PhysicalDriveB,(LPARAM)0); @@ -413,10 +413,10 @@ void Load_Disk(unsigned char disk) if (dlg.show(0,h_own)) { CreateFlag = 1; HANDLE hr = nullptr; - dlg.getpath(TempFileName,MAX_PATH); + dlg.getpath(gSelectedDiskFile,MAX_PATH); // Verify file exists hr = CreateFile - (TempFileName,0,FILE_SHARE_READ,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + (gSelectedDiskFile,0,FILE_SHARE_READ,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); // Create new disk file if it does not if (hr == INVALID_HANDLE_VALUE) { NewDiskNumber = disk; @@ -427,7 +427,7 @@ void Load_Disk(unsigned char disk) } // Attempt mount if file existed or file create was not canceled if (CreateFlag==1) { - if (mount_disk_image(TempFileName,disk)==0) { + if (mount_disk_image(gSelectedDiskFile,disk)==0) { MessageBox(g_hConfDlg,"Can't open file","Error",0); } else { dlg.getdir(FloppyPath); @@ -447,7 +447,7 @@ unsigned char SetChip(unsigned char Tmp) void BuildCartridgeMenu() { - char TempMsg[64]=""; + char TempMsg[MAX_PATH]=""; char TempBuf[MAX_PATH]=""; if (CartMenuCallback ==nullptr) MessageBox(g_hConfDlg,"No good","Ok",0); @@ -457,34 +457,34 @@ void BuildCartridgeMenu() CartMenuCallback(gCallbackContext, "FD-502 Drive 0",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(10),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[0].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[0].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(11),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 1",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(12),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[1].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[1].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(13),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 2",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(14),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[2].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[2].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(15),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 3",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(17),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[3].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[3].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(18),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Config",ControlId(16),MIT_StandAlone); @@ -519,7 +519,7 @@ LRESULT CALLBACK NewDisk(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam for (temp=0;temp<=2;temp++) SendDlgItemMessage(hDlg,DiskTracks[temp],BM_SETCHECK,(temp==NewDiskTracks),0); SendDlgItemMessage(hDlg,IDC_DBLSIDE,BM_SETCHECK,DblSided,0); - strcpy(Dummy,TempFileName); + strcpy(Dummy,gSelectedDiskFile); PathStripPath(Dummy); SendDlgItemMessage(hDlg,IDC_TEXT1,WM_SETTEXT,0,(LPARAM)(LPCSTR)Dummy); return TRUE; @@ -561,17 +561,17 @@ LRESULT CALLBACK NewDisk(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam case IDOK: { EndDialog(hDlg, LOWORD(wParam)); - const char *ext = TempFileName + strlen(TempFileName) - 4; - if (ext < TempFileName) ext = TempFileName; + const char *ext = gSelectedDiskFile + strlen(gSelectedDiskFile) - 4; + if (ext < gSelectedDiskFile) ext = gSelectedDiskFile; // if it doesn't end with .dsk, append it if (_stricmp(ext, ".dsk") != 0) { - PathRemoveExtension(TempFileName); - strcat(TempFileName, ".dsk"); + PathRemoveExtension(gSelectedDiskFile); + strcat(gSelectedDiskFile, ".dsk"); } - if (CreateDiskHeader(TempFileName, NewDiskType, NewDiskTracks, DblSided)) + if (CreateDiskHeader(gSelectedDiskFile, NewDiskType, NewDiskTracks, DblSided)) { - strcpy(TempFileName, ""); + strcpy(gSelectedDiskFile, ""); MessageBox(g_hConfDlg, "Can't create File", "Error", 0); } return TRUE; @@ -732,7 +732,7 @@ void SaveConfig() for (Index=0;Index<4;Index++) { sprintf(Temp,"Disk#%i",Index); - WritePrivateProfileString(ModName,Temp,Drive[Index].ImageName,IniFile); + WritePrivateProfileString(ModName,Temp,gVirtualDrive[Index].ImageName,IniFile); } WritePrivateProfileInt(ModName,"ClkEnable",ClockEnabled ,IniFile); WritePrivateProfileInt(ModName, "TurboDisk", SetTurboDisk(QUERY), IniFile); diff --git a/FD502/wd1793.cpp b/FD502/wd1793.cpp index 24a1e00e..90cf5082 100644 --- a/FD502/wd1793.cpp +++ b/FD502/wd1793.cpp @@ -28,6 +28,7 @@ This file is part of VCC (Virtual Color Computer). * Last change date 06/27/2006 seek time more closely emulated * * Last change date 05/16/2007 Better DMK support. Diecom protection works now * * Last change date 05/21/2007 Added fdrawcmd support for real disk access/ * +* Last change date 02/07/2026 EJJ Sanitize variable names * * * ********************************************************************************/ //#define USE_LOGGING @@ -75,7 +76,7 @@ bool CmdFormat (HANDLE , PFD_FORMAT_PARAMS , ULONG ); static unsigned char StepTimesMS[4]={6,12,20,30}; static unsigned short BytesperSector[4]={128,256,512,1024}; static unsigned char TransferBuffer[16384]=""; -DiskInfo Drive[5]; +DiskInfo gVirtualDrive[5]; static unsigned char StatusReg=READY; static unsigned char DataReg=0; static unsigned char TrackReg=0; @@ -220,8 +221,8 @@ void DecodeControlReg(unsigned char Tmp) if (Tmp & CTRL_MOTOR_EN) { MotorOn=1; - if ( Drive[CurrentDisk].ImageType == RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle, IOCTL_FD_MOTOR_ON, nullptr, 0, nullptr, 0, &dwRet, nullptr); + if ( gVirtualDrive[CurrentDisk].ImageType == RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle, IOCTL_FD_MOTOR_ON, nullptr, 0, nullptr, 0, &dwRet, nullptr); } if ( (Side==1) & (CurrentDisk==NONE) ) @@ -253,11 +254,11 @@ int mount_disk_image(const char *filename,unsigned char drive) void unmount_disk_image(unsigned char drive) { - if (Drive[drive].FileHandle !=nullptr) - CloseHandle(Drive[drive].FileHandle); - Drive[drive].FileHandle=nullptr; - Drive[drive].ImageType=0; - strcpy(Drive[drive].ImageName,""); + if (gVirtualDrive[drive].FileHandle !=nullptr) + CloseHandle(gVirtualDrive[drive].FileHandle); + gVirtualDrive[drive].FileHandle=nullptr; + gVirtualDrive[drive].ImageType=0; + strcpy(gVirtualDrive[drive].ImageName,""); DirtyDisk=true; if (drive==(PhysicalDriveA-1)) PhysicalDriveA=0; @@ -269,7 +270,7 @@ void unmount_disk_image(unsigned char drive) void DiskStatus(char* text_buffer, size_t buffer_size) { if (MotorOn==1) - sprintf(text_buffer,"FD-502:Drv:%1.1i %s Trk:%2.2i Sec:%2.2i Hd:%1.1i",CurrentDisk,ImageFormat[Drive[CurrentDisk].ImageType],Drive[CurrentDisk].HeadPosition,SectorReg,Side); + sprintf(text_buffer,"FD-502:Drv:%1.1i %s Trk:%2.2i Sec:%2.2i Hd:%1.1i",CurrentDisk,ImageFormat[gVirtualDrive[CurrentDisk].ImageType],gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,Side); else sprintf(text_buffer,"FD-502:Idle"); } @@ -281,49 +282,49 @@ unsigned char MountDisk(const char *FileName,unsigned char disk) long TotalSectors=0; unsigned char TmpSides=0,TmpSectors=0,TmpMod=0; - if (Drive[disk].FileHandle !=nullptr) + if (gVirtualDrive[disk].FileHandle !=nullptr) unmount_disk_image(disk); //Image Geometry Defaults - Drive[disk].FirstSector=1; - Drive[disk].Sides=1; - Drive[disk].Sectors=18; - Drive[disk].SectorSize=1; - Drive[disk].WriteProtect=0; - Drive[disk].RawDrive=0; + gVirtualDrive[disk].FirstSector=1; + gVirtualDrive[disk].Sides=1; + gVirtualDrive[disk].Sectors=18; + gVirtualDrive[disk].SectorSize=1; + gVirtualDrive[disk].WriteProtect=0; + gVirtualDrive[disk].RawDrive=0; if (!strcmp(FileName,"*Floppy A:")) - Drive[disk].RawDrive=1; + gVirtualDrive[disk].RawDrive=1; if (!strcmp(FileName,"*Floppy B:")) - Drive[disk].RawDrive=2; + gVirtualDrive[disk].RawDrive=2; - if (Drive[disk].RawDrive==0) + if (gVirtualDrive[disk].RawDrive==0) { - Drive[disk].FileHandle = CreateFile( FileName,GENERIC_READ | GENERIC_WRITE,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); - if (Drive[disk].FileHandle==INVALID_HANDLE_VALUE) + gVirtualDrive[disk].FileHandle = CreateFile( FileName,GENERIC_READ | GENERIC_WRITE,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + if (gVirtualDrive[disk].FileHandle==INVALID_HANDLE_VALUE) { //Can't open read/write might be read only - Drive[disk].FileHandle = CreateFile(FileName,GENERIC_READ,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); - Drive[disk].WriteProtect=0xFF; + gVirtualDrive[disk].FileHandle = CreateFile(FileName,GENERIC_READ,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + gVirtualDrive[disk].WriteProtect=0xFF; } - if (Drive[disk].FileHandle==INVALID_HANDLE_VALUE) + if (gVirtualDrive[disk].FileHandle==INVALID_HANDLE_VALUE) return 1; //Give up cant mount it - strcpy(Drive[disk].ImageName,FileName); - Drive[disk].FileSize= GetFileSize(Drive[disk].FileHandle,nullptr); - Drive[disk].HeaderSize = Drive[disk].FileSize % 256; - SetFilePointer(Drive[disk].FileHandle,0,nullptr,FILE_BEGIN); - ReadFile(Drive[disk].FileHandle,HeaderBlock,HEADERBUFFERSIZE,&BytesRead,nullptr); + strcpy(gVirtualDrive[disk].ImageName,FileName); + gVirtualDrive[disk].FileSize= GetFileSize(gVirtualDrive[disk].FileHandle,nullptr); + gVirtualDrive[disk].HeaderSize = gVirtualDrive[disk].FileSize % 256; + SetFilePointer(gVirtualDrive[disk].FileHandle,0,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[disk].FileHandle,HeaderBlock,HEADERBUFFERSIZE,&BytesRead,nullptr); } else - Drive[disk].HeaderSize=0xFF; + gVirtualDrive[disk].HeaderSize=0xFF; - switch (Drive[disk].HeaderSize) + switch (gVirtualDrive[disk].HeaderSize) { case 4: - Drive[disk].FirstSector=HeaderBlock[3]; + gVirtualDrive[disk].FirstSector=HeaderBlock[3]; case 3: - Drive[disk].SectorSize=HeaderBlock[2]; + gVirtualDrive[disk].SectorSize=HeaderBlock[2]; case 2: - Drive[disk].Sectors = HeaderBlock[0]; - Drive[disk].Sides = HeaderBlock[1]; + gVirtualDrive[disk].Sectors = HeaderBlock[0]; + gVirtualDrive[disk].Sides = HeaderBlock[1]; case 0: //OS9 Image checks @@ -333,53 +334,53 @@ unsigned char MountDisk(const char *FileName,unsigned char disk) TmpMod=1; if ( (TmpSides*TmpSectors)!=0) TmpMod = TotalSectors%(TmpSides*TmpSectors); - if ((TmpSectors ==18) & (TmpMod==0) & (Drive[disk].HeaderSize ==0)) //Sanity Check + if ((TmpSectors ==18) & (TmpMod==0) & (gVirtualDrive[disk].HeaderSize ==0)) //Sanity Check { - Drive[disk].ImageType=OS9; - Drive[disk].Sides = TmpSides; - Drive[disk].Sectors = TmpSectors; + gVirtualDrive[disk].ImageType=OS9; + gVirtualDrive[disk].Sides = TmpSides; + gVirtualDrive[disk].Sectors = TmpSectors; } else - Drive[disk].ImageType=JVC; - Drive[disk].TrackSize = Drive[disk].Sectors * BytesperSector[Drive[disk].SectorSize]; + gVirtualDrive[disk].ImageType=JVC; + gVirtualDrive[disk].TrackSize = gVirtualDrive[disk].Sectors * BytesperSector[gVirtualDrive[disk].SectorSize]; break; case 12: - Drive[disk].ImageType=VDK; //VDK - Drive[disk].Sides = HeaderBlock[9]; - Drive[disk].TrackSize = Drive[disk].Sectors * BytesperSector[Drive[disk].SectorSize]; + gVirtualDrive[disk].ImageType=VDK; //VDK + gVirtualDrive[disk].Sides = HeaderBlock[9]; + gVirtualDrive[disk].TrackSize = gVirtualDrive[disk].Sectors * BytesperSector[gVirtualDrive[disk].SectorSize]; break; case 16: - Drive[disk].ImageType=DMK; //DMK - if (Drive[disk].WriteProtect != 0xFF) - Drive[disk].WriteProtect = HeaderBlock[0]; - Drive[disk].TrackSize = (HeaderBlock[3]<<8 | HeaderBlock[2]); - Drive[disk].Sides = 2-((HeaderBlock[4] & 16 )>>4); + gVirtualDrive[disk].ImageType=DMK; //DMK + if (gVirtualDrive[disk].WriteProtect != 0xFF) + gVirtualDrive[disk].WriteProtect = HeaderBlock[0]; + gVirtualDrive[disk].TrackSize = (HeaderBlock[3]<<8 | HeaderBlock[2]); + gVirtualDrive[disk].Sides = 2-((HeaderBlock[4] & 16 )>>4); break; case 0xFF: - if (Drive[disk].RawDrive) + if (gVirtualDrive[disk].RawDrive) { - if (Drive[disk].FileHandle !=nullptr) + if (gVirtualDrive[disk].FileHandle !=nullptr) unmount_disk_image(disk); - Drive[disk].ImageType=RAW; - Drive[disk].Sides=2; + gVirtualDrive[disk].ImageType=RAW; + gVirtualDrive[disk].Sides=2; - Drive[disk].FileHandle = OpenFloppy(Drive[disk].RawDrive-1); - if (Drive[disk].FileHandle == nullptr) + gVirtualDrive[disk].FileHandle = OpenFloppy(gVirtualDrive[disk].RawDrive-1); + if (gVirtualDrive[disk].FileHandle == nullptr) return 1; - strcpy(Drive[disk].ImageName,FileName); - if (Drive[disk].RawDrive==1) + strcpy(gVirtualDrive[disk].ImageName,FileName); + if (gVirtualDrive[disk].RawDrive==1) PhysicalDriveA=disk+1; - if (Drive[disk].RawDrive==2) + if (gVirtualDrive[disk].RawDrive==2) PhysicalDriveB=disk+1; } break; default: return 1; } - strncpy(Drive[disk].ImageTypeName,ImageFormat[Drive[disk].ImageType],4); + strncpy(gVirtualDrive[disk].ImageTypeName,ImageFormat[gVirtualDrive[disk].ImageType],4); return 0; //Return 0 on success } @@ -403,43 +404,43 @@ long ReadSector (unsigned char Side, //0 or 1 const unsigned char *pva=nullptr; //************************ - if (Drive[CurrentDisk].FileHandle==nullptr) + if (gVirtualDrive[CurrentDisk].FileHandle==nullptr) return 0; - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - if (((Side+1) > Drive[CurrentDisk].Sides) | (TrackReg != Drive[CurrentDisk].HeadPosition)) + if (((Side+1) > gVirtualDrive[CurrentDisk].Sides) | (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition)) return 0; - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize) + (BytesperSector[Drive[CurrentDisk].SectorSize] * (Sector - Drive[CurrentDisk].FirstSector) ) ) ; + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize) + (BytesperSector[gVirtualDrive[CurrentDisk].SectorSize] * (Sector - gVirtualDrive[CurrentDisk].FirstSector) ) ) ; DLOG_C("FDC S%d trk:%d side:%d sect:%d hsiz:%d nside:%d tsiz:%d ssiz:%d fsec:%d\n", FileOffset, Track, Side, Sector, - Drive[CurrentDisk].HeaderSize, - Drive[CurrentDisk].Sides, - Drive[CurrentDisk].TrackSize, - BytesperSector[Drive[CurrentDisk].SectorSize], - Drive[CurrentDisk].FirstSector); - - SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,ReturnBuffer,BytesperSector[Drive[CurrentDisk].SectorSize],&BytesRead,nullptr); - if (BytesRead != BytesperSector[Drive[CurrentDisk].SectorSize]) //Fake the read for short images + gVirtualDrive[CurrentDisk].HeaderSize, + gVirtualDrive[CurrentDisk].Sides, + gVirtualDrive[CurrentDisk].TrackSize, + BytesperSector[gVirtualDrive[CurrentDisk].SectorSize], + gVirtualDrive[CurrentDisk].FirstSector); + + SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,ReturnBuffer,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize],&BytesRead,nullptr); + if (BytesRead != BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]) //Fake the read for short images { - memset(ReturnBuffer,0xFF,BytesperSector[Drive[CurrentDisk].SectorSize]); - BytesRead=BytesperSector[Drive[CurrentDisk].SectorSize]; + memset(ReturnBuffer,0xFF,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]); + BytesRead=BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]; } - return(BytesperSector[Drive[CurrentDisk].SectorSize]); + return(BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]); case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); //Need to read the entire track due to the emulation of interleave on these images - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); - if (BytesRead!=Drive[CurrentDisk].TrackSize) //DMK can't be short the image is corupt + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); + if (BytesRead!=gVirtualDrive[CurrentDisk].TrackSize) //DMK can't be short the image is corupt return 0; CurrentSector.Sector=Sector; if (GetSectorInfo (&CurrentSector,TempBuffer)==0) @@ -449,14 +450,14 @@ long ReadSector (unsigned char Side, //0 or 1 case RAW: pva=(unsigned char *)RawReadBuf; - if (TrackReg != Drive[CurrentDisk].HeadPosition) + if (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition) return 0; //Read the entire track and cache it. Speeds up disk reads - if (DirtyDisk | (rwp.phead != Side) | (rwp.cyl != Drive[CurrentDisk].HeadPosition ) ) + if (DirtyDisk | (rwp.phead != Side) | (rwp.cyl != gVirtualDrive[CurrentDisk].HeadPosition ) ) { rwp.flags = FD_OPTION_MFM; rwp.phead = Side; - rwp.cyl = Drive[CurrentDisk].HeadPosition; + rwp.cyl = gVirtualDrive[CurrentDisk].HeadPosition; rwp.head = Side; rwp.sector = 1; rwp.size = 1; //256 Byte Secotors @@ -467,8 +468,8 @@ long ReadSector (unsigned char Side, //0 or 1 sp.cyl = Track; sp.head = Side; // seek to cyl - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &sp, sizeof(sp), nullptr, 0, &dwRet, nullptr); - Ret=DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_READ_DATA, &rwp, sizeof(rwp), RawReadBuf,4608, &dwRet, nullptr); + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &sp, sizeof(sp), nullptr, 0, &dwRet, nullptr); + Ret=DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_READ_DATA, &rwp, sizeof(rwp), RawReadBuf,4608, &dwRet, nullptr); if (dwRet != 4608) return 0; DirtyDisk=false; @@ -496,25 +497,25 @@ long WriteSector ( unsigned char Side, //0 or 1 unsigned char Ret=0; const unsigned char *pva=nullptr; SectorInfo CurrentSector; - if ( (Drive[CurrentDisk].FileHandle==nullptr) | ((Side+1) > Drive[CurrentDisk].Sides) ) + if ( (gVirtualDrive[CurrentDisk].FileHandle==nullptr) | ((Side+1) > gVirtualDrive[CurrentDisk].Sides) ) return 0; - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize) + (BytesperSector[Drive[CurrentDisk].SectorSize] * (Sector - Drive[CurrentDisk].FirstSector) ) ) ; - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - WriteFile(Drive[CurrentDisk].FileHandle,WriteBuffer,BytesperSector[Drive[CurrentDisk].SectorSize],&BytesWritten,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize) + (BytesperSector[gVirtualDrive[CurrentDisk].SectorSize] * (Sector - gVirtualDrive[CurrentDisk].FirstSector) ) ) ; + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + WriteFile(gVirtualDrive[CurrentDisk].FileHandle,WriteBuffer,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize],&BytesWritten,nullptr); return BytesWritten; case DMK: //DMK - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); //Need to read the entire track due to the emulation of interleave on these images - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); - if (BytesRead!=Drive[CurrentDisk].TrackSize) + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); + if (BytesRead!=gVirtualDrive[CurrentDisk].TrackSize) return 0; CurrentSector.Sector=Sector; @@ -525,9 +526,9 @@ long WriteSector ( unsigned char Side, //0 or 1 Crc=ccitt_crc16(0xE295,&TempBuffer[CurrentSector.DAM] , CurrentSector.Lenth); //0xcdb4 TempBuffer[CurrentSector.DAM + CurrentSector.Lenth ] =Crc>>8; TempBuffer[CurrentSector.DAM + CurrentSector.Lenth +1 ] =(Crc & 0xFF); - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - WriteFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesWritten,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + WriteFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesWritten,nullptr); return(CurrentSector.Lenth); case RAW: @@ -535,7 +536,7 @@ long WriteSector ( unsigned char Side, //0 or 1 pva=(unsigned char *) RawReadBuf; rwp.flags = FD_OPTION_MFM; rwp.phead = Side; - rwp.cyl = Drive[CurrentDisk].HeadPosition; + rwp.cyl = gVirtualDrive[CurrentDisk].HeadPosition; rwp.head = Side; rwp.sector = Sector; rwp.size = 1; //256 Byte Secotors @@ -546,9 +547,9 @@ long WriteSector ( unsigned char Side, //0 or 1 sp.cyl = Track; sp.head = Side; // seek to cyl - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &Track, sizeof(Track), nullptr, 0, &dwRet, nullptr); + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &Track, sizeof(Track), nullptr, 0, &dwRet, nullptr); memcpy(RawReadBuf,WriteBuffer,256); - Ret=DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_WRITE_DATA, &rwp, sizeof(rwp), RawReadBuf,18*(128< Drive[CurrentDisk].Sides) + if ((Side+1) > gVirtualDrive[CurrentDisk].Sides) return 0; //STUB Write Me return 0; case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)+128); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,WriteBuffer,(Drive[CurrentDisk].TrackSize-128),&BytesRead,nullptr); - if (BytesRead != ((unsigned)Drive[CurrentDisk].TrackSize-128) ) + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)+128); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,WriteBuffer,(gVirtualDrive[CurrentDisk].TrackSize-128),&BytesRead,nullptr); + if (BytesRead != ((unsigned)gVirtualDrive[CurrentDisk].TrackSize-128) ) return 0; break; } @@ -703,7 +704,7 @@ void PingFdc() wobble/=4; } - if ( ((CurrentCommand<=7) | (CurrentCommand==IDLE)) & (Drive[CurrentDisk].FileHandle!=nullptr) ) + if ( ((CurrentCommand<=7) | (CurrentCommand==IDLE)) & (gVirtualDrive[CurrentDisk].FileHandle!=nullptr) ) { if (IndexPulse ) StatusReg|=INDEXPULSE; @@ -722,56 +723,56 @@ void PingFdc() switch (CurrentCommand) { case RESTORE: - if (Drive[CurrentDisk].HeadPosition!=0) + if (gVirtualDrive[CurrentDisk].HeadPosition!=0) { - Drive[CurrentDisk].HeadPosition-=1; + gVirtualDrive[CurrentDisk].HeadPosition-=1; ExecTimeWaiter=(CyclesperStep * StepTimeMS); - if (Drive[CurrentDisk].ImageType==RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, nullptr, 1, nullptr, 0, &dwRet, nullptr); + if (gVirtualDrive[CurrentDisk].ImageType==RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, nullptr, 1, nullptr, 0, &dwRet, nullptr); } else { TrackReg=0; StatusReg=READY; StatusReg|=TRACK_ZERO; - Drive[CurrentDisk].HeadPosition=0; - if (Drive[CurrentDisk].WriteProtect) + gVirtualDrive[CurrentDisk].HeadPosition=0; + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; CommandDone(); } break; case SEEK: - if (Drive[CurrentDisk].HeadPosition!=DataReg) + if (gVirtualDrive[CurrentDisk].HeadPosition!=DataReg) { if (StepDirection==1) - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; else - Drive[CurrentDisk].HeadPosition-=1; + gVirtualDrive[CurrentDisk].HeadPosition-=1; ExecTimeWaiter=(CyclesperStep * StepTimeMS); } else { - Drive[CurrentDisk].HeadPosition=TrackReg; + gVirtualDrive[CurrentDisk].HeadPosition=TrackReg; StatusReg=READY; - if (Drive[CurrentDisk].HeadPosition==0) + if (gVirtualDrive[CurrentDisk].HeadPosition==0) StatusReg|=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; CommandDone(); } - if (Drive[CurrentDisk].ImageType==RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &TrackReg, sizeof(TrackReg), nullptr, 0, &dwRet, nullptr); + if (gVirtualDrive[CurrentDisk].ImageType==RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &TrackReg, sizeof(TrackReg), nullptr, 0, &dwRet, nullptr); break; case STEP: case STEPUPD: if (StepDirection==1) - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; else { - if (Drive[CurrentDisk].HeadPosition >0) - Drive[CurrentDisk].HeadPosition-=1; + if (gVirtualDrive[CurrentDisk].HeadPosition >0) + gVirtualDrive[CurrentDisk].HeadPosition-=1; } if (CurrentCommand & 1) @@ -781,9 +782,9 @@ void PingFdc() else TrackReg-=1; } - if ( Drive[CurrentDisk].HeadPosition == 0) + if ( gVirtualDrive[CurrentDisk].HeadPosition == 0) StatusReg=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -792,10 +793,10 @@ void PingFdc() case STEPIN: case STEPINUPD: StepDirection=1; - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; if (CurrentCommand & 1) TrackReg+=1; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -804,13 +805,13 @@ void PingFdc() case STEPOUT: case STEPOUTUPD: StepDirection=0; - if ( Drive[CurrentDisk].HeadPosition > 0 ) - Drive[CurrentDisk].HeadPosition-=1; + if ( gVirtualDrive[CurrentDisk].HeadPosition > 0 ) + gVirtualDrive[CurrentDisk].HeadPosition-=1; if (CurrentCommand & 1) TrackReg-=1; - if ( Drive[CurrentDisk].HeadPosition == 0) + if ( gVirtualDrive[CurrentDisk].HeadPosition == 0) StatusReg=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -890,7 +891,7 @@ void DispatchCommand(unsigned char Tmp) ExecTimeWaiter= CyclestoSettle + (CyclesperStep * StepTimeMS); TrackReg=DataReg; StatusReg= BUSY; - if ( Drive[CurrentDisk].HeadPosition > DataReg) + if ( gVirtualDrive[CurrentDisk].HeadPosition > DataReg) StepDirection=0; else StepDirection=1; @@ -997,11 +998,11 @@ unsigned char GetBytefromSector () if (TransferBufferSize == 0) { - TransferBufferSize = ReadSector(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + TransferBufferSize = ReadSector(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); // WriteLog("BEGIN Readsector",0); } - if (TransferBufferSize==0)// IRON| (TrackReg != Drive[CurrentDrive].HeadPosition) ) //| (SectorReg > Drive[CurrentDrive].Sectors) + if (TransferBufferSize==0)// IRON| (TrackReg != gVirtualDrive[CurrentDrive].HeadPosition) ) //| (SectorReg > gVirtualDrive[CurrentDrive].Sectors) { CommandDone(); StatusReg=RECNOTFOUND; @@ -1037,25 +1038,25 @@ unsigned char GetBytefromAddress () if (TransferBufferSize == 0) { - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - TransferBuffer[0]= Drive[CurrentDisk].HeadPosition; - TransferBuffer[1]= Drive[CurrentDisk].Sides; + TransferBuffer[0]= gVirtualDrive[CurrentDisk].HeadPosition; + TransferBuffer[1]= gVirtualDrive[CurrentDisk].Sides; TransferBuffer[2]= IndexCounter/176; - TransferBuffer[3]= Drive[CurrentDisk].SectorSize; + TransferBuffer[3]= gVirtualDrive[CurrentDisk].SectorSize; TransferBuffer[4]= (Crc >> 8); TransferBuffer[5]= (Crc & 0xFF); TransferBufferSize=6; break; case DMK: - TransferBuffer[0]= Drive[CurrentDisk].HeadPosition; //CurrentSector.Track; not right need to get from image - TransferBuffer[1]= Drive[CurrentDisk].Sides; + TransferBuffer[0]= gVirtualDrive[CurrentDisk].HeadPosition; //CurrentSector.Track; not right need to get from image + TransferBuffer[1]= gVirtualDrive[CurrentDisk].Sides; TransferBuffer[2]= IndexCounter/176; - TransferBuffer[3]= IndexCounter/176; //Drive[CurrentDrive].SectorSize; + TransferBuffer[3]= IndexCounter/176; //gVirtualDrive[CurrentDrive].SectorSize; Crc = 0;//CurrentSector.CRC; TransferBuffer[4]= (Crc >> 8); TransferBuffer[5]= (Crc & 0xFF); @@ -1064,7 +1065,7 @@ unsigned char GetBytefromAddress () } //END Switch } - if ( Drive[CurrentDisk].FileHandle==nullptr ) + if ( gVirtualDrive[CurrentDisk].FileHandle==nullptr ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1096,11 +1097,11 @@ unsigned char GetBytefromTrack () if (TransferBufferSize == 0) { - TransferBufferSize = ReadTrack(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + TransferBufferSize = ReadTrack(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); // WriteLog("BEGIN READTRACK",0); } - if (TransferBufferSize==0)//iron | (TrackReg != Drive[CurrentDrive].HeadPosition) ) //| (SectorReg > Drive[CurrentDrive].Sectors) + if (TransferBufferSize==0)//iron | (TrackReg != gVirtualDrive[CurrentDrive].HeadPosition) ) //| (SectorReg > gVirtualDrive[CurrentDrive].Sectors) { CommandDone(); StatusReg=RECNOTFOUND; @@ -1138,13 +1139,13 @@ unsigned char WriteBytetoSector (unsigned char Tmp) if (TransferBufferSize==0) { // WriteLog("Begining WriteSector data collection Command",0); - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - TransferBufferSize=BytesperSector[Drive[CurrentDisk].SectorSize]; - if ((TransferBufferSize==0) | (TrackReg != Drive[CurrentDisk].HeadPosition) | (SectorReg > Drive[CurrentDisk].Sectors) ) + TransferBufferSize=BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]; + if ((TransferBufferSize==0) | (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition) | (SectorReg > gVirtualDrive[CurrentDisk].Sectors) ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1153,12 +1154,12 @@ unsigned char WriteBytetoSector (unsigned char Tmp) break; case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Drive[CurrentDisk].HeadPosition * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (gVirtualDrive[CurrentDisk].HeadPosition * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); CurrentSector.Sector=SectorReg; GetSectorInfo(&CurrentSector,TempBuffer); - if ( (CurrentSector.DAM == 0) | (BytesRead != Drive[CurrentDisk].TrackSize) ) + if ( (CurrentSector.DAM == 0) | (BytesRead != gVirtualDrive[CurrentDisk].TrackSize) ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1175,11 +1176,11 @@ unsigned char WriteBytetoSector (unsigned char Tmp) if (TransferBufferIndex>=TransferBufferSize) { - RetVal=WriteSector(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer,TransferBufferSize); + RetVal=WriteSector(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer,TransferBufferSize); StatusReg=READY; if (( RetVal==0) | (LostDataFlag==1) ) StatusReg=LOSTDATA; - if (Drive[CurrentDisk].WriteProtect != 0) + if (gVirtualDrive[CurrentDisk].WriteProtect != 0) StatusReg=WRITEPROTECT | RECNOTFOUND; CommandDone(); LostDataFlag=0; @@ -1202,12 +1203,12 @@ unsigned char WriteBytetoTrack (unsigned char Tmp) if (TransferBufferIndex>=TransferBufferSize) { - RetVal=WriteTrack(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + RetVal=WriteTrack(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); StatusReg=READY; if (( RetVal==0) | (LostDataFlag==1) ) StatusReg=LOSTDATA; - if (Drive[CurrentDisk].WriteProtect != 0) + if (gVirtualDrive[CurrentDisk].WriteProtect != 0) StatusReg=WRITEPROTECT | RECNOTFOUND; CommandDone(); LostDataFlag=0; @@ -1275,7 +1276,7 @@ long GetSectorInfo (SectorInfo *Sector,const unsigned char *TempBuffer) { Temp1= (TempBuffer[IdamIndex+1]<<8) | TempBuffer[IdamIndex]; //Reverse Bytes and Get the pointer Density= Temp1>>15; //Density flag - Temp1= (0x3FFF & Temp1) % Drive[CurrentDisk].TrackSize; //Mask and keep from overflowing + Temp1= (0x3FFF & Temp1) % gVirtualDrive[CurrentDisk].TrackSize; //Mask and keep from overflowing IdamIndex+=2; } while ( (IdamIndex<128) & (Temp1 !=0) & (Sector->Sector != TempBuffer[Temp1+3]) ); diff --git a/libcommon/src/bus/CartridgeInterface.txt b/libcommon/src/bus/CartridgeInterface.txt index 16e7a895..168da28a 100644 --- a/libcommon/src/bus/CartridgeInterface.txt +++ b/libcommon/src/bus/CartridgeInterface.txt @@ -173,7 +173,7 @@ cartridge UI that require future changes or additions should use these callbacks In the current codebase the messaging mechanism is already being used for a callback. When the MPI needs to initiate a hard VCC reset is does so by sending a message to WinMain. -The add_menu_item callback is not tied to the CPU loop and qualifies as a slot callback. +The add_menu_item callback is not tied to the CPU loop and qualifies as a slow callback. This callback will be replaced by a Windows message. --- diff --git a/libcommon/src/util/FileOps.cpp b/libcommon/src/util/FileOps.cpp index ebc95b29..dd5e21df 100644 --- a/libcommon/src/util/FileOps.cpp +++ b/libcommon/src/util/FileOps.cpp @@ -72,7 +72,7 @@ void PathStripPath ( char *TextBuffer) return; for (; Index >= 0; Index--) - if (TextBuffer[Index] == '\\') + if (TextBuffer[Index] == '\\' || TextBuffer[Index] == '/') break; if (Index < 0) //delimiter not found