diff --git a/stepmania/src/PrefsManager.h b/stepmania/src/PrefsManager.h
index d719c6d000..8ee9fcd826 100644
--- a/stepmania/src/PrefsManager.h
+++ b/stepmania/src/PrefsManager.h
@@ -178,7 +178,7 @@ public:
int m_iEndlessBreakLength;
bool m_bDisableScreenSaver;
CString m_sLanguage;
- CString m_sMemoryCardProfileSubdir; // if set, always use the device that mounts to this point
+ CString m_sMemoryCardProfileSubdir; // the directory on a memory card to look in for a profile
CString m_sDefaultLocalProfileID[NUM_PLAYERS];
CString m_sMemoryCardOsMountPoint[NUM_PLAYERS]; // if set, always use the device that mounts to this point
int m_iMemoryCardUsbBus[NUM_PLAYERS]; // take the first storage device on this usb bus
diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp
index a2f9106de0..63a293bf53 100644
--- a/stepmania/src/StepMania.dsp
+++ b/stepmania/src/StepMania.dsp
@@ -1,5 +1,5 @@
# Microsoft Developer Studio Project File - Name="StepMania" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# Microsoft Developer Studio Generated Build File, Format Version 60000
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
@@ -62,10 +62,10 @@ LINK32=link.exe
# SUBTRACT LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib
# Begin Special Build Tool
IntDir=.\../Debug6
-TargetDir=\temp\stepmania\Program
+TargetDir=\stepmania\stepmania\Program
TargetName=StepMania-debug
SOURCE="$(InputPath)"
-PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
+PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi
# End Special Build Tool
@@ -135,10 +135,10 @@ LINK32=link.exe
# SUBTRACT LINK32 /verbose /pdb:none /debug
# Begin Special Build Tool
IntDir=.\../Release6
-TargetDir=\temp\stepmania\Program
+TargetDir=\stepmania\stepmania\Program
TargetName=StepMania
SOURCE="$(InputPath)"
-PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
+PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi
# End Special Build Tool
@@ -2657,26 +2657,41 @@ SOURCE=.\arch\MemoryCard\MemoryCardDriver_Null.h
# End Source File
# Begin Source File
-SOURCE=.\arch\MemoryCard\MemoryCardDriver_Windows.cpp
+SOURCE=.\arch\MemoryCard\MemoryCardDriverThreaded.cpp
!IF "$(CFG)" == "StepMania - Win32 Debug"
!ELSEIF "$(CFG)" == "StepMania - Xbox Debug"
-# PROP Exclude_From_Build 1
-
!ELSEIF "$(CFG)" == "StepMania - Win32 Release"
!ELSEIF "$(CFG)" == "StepMania - Xbox Release"
-# PROP Exclude_From_Build 1
-
!ENDIF
# End Source File
# Begin Source File
-SOURCE=.\arch\MemoryCard\MemoryCardDriver_Windows.h
+SOURCE=.\arch\MemoryCard\MemoryCardDriverThreaded.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\arch\MemoryCard\MemoryCardDriverThreaded_Windows.cpp
+
+!IF "$(CFG)" == "StepMania - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "StepMania - Xbox Debug"
+
+!ELSEIF "$(CFG)" == "StepMania - Win32 Release"
+
+!ELSEIF "$(CFG)" == "StepMania - Xbox Release"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\arch\MemoryCard\MemoryCardDriverThreaded_Windows.h
# End Source File
# End Group
# Begin Source File
diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj
index e6f06b1d1a..6e621f5fa9 100644
--- a/stepmania/src/StepMania.vcproj
+++ b/stepmania/src/StepMania.vcproj
@@ -1097,15 +1097,21 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\
+
+
+
+
+
+
+
+
-
-
-
-
MountThreadMain();
+ return 0;
+}
+
+template
+bool VectorsAreEqual( const T &a, const T &b )
+{
+ if( a.size() != b.size() )
+ return false;
+
+ for( unsigned i=0; iTrace( "Shutting down Mount thread..." );
+ m_threadMemoryCardMount.Wait();
+ LOG->Trace( "Mount thread shut down." );
+}
+
+bool MemoryCardDriverThreaded::StorageDevicesChanged()
+{
+ LockMut( m_mutexStorageDevices );
+ if( m_bStorageDevicesChanged )
+ {
+ m_bStorageDevicesChanged = false;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void MemoryCardDriverThreaded::GetStorageDevices( vector& vDevicesOut )
+{
+ LockMut( m_mutexStorageDevices );
+ vDevicesOut.clear();
+ for( unsigned i=0; i::const_iterator iter = find( m_vStorageDevices.begin(), m_vStorageDevices.end(), *pDevice );
+ if( iter == m_vStorageDevices.end() )
+ {
+ LOG->Warn( "Tried to mount a memory card that is no longer connected" );
+ return false;
+ }
+
+ if( !iter->bWriteTestSucceeded )
+ return false;
+
+ this->Mount( pDevice, sMountPoint );
+ return true;
+}
+
+/*
+* Copyright (c) 2003 by the person(s) listed below. All rights reserved.
+* Chris Danford
+*/
diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded.h b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded.h
new file mode 100644
index 0000000000..5a55374956
--- /dev/null
+++ b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded.h
@@ -0,0 +1,57 @@
+#ifndef MemoryCardDriverThreaded_H
+#define MemoryCardDriverThreaded_H 1
+/*
+-----------------------------------------------------------------------------
+ Class: MemoryCardDriverThreaded
+
+ Desc: Adapter .
+
+ Copyright (c) 2001-2004 by the person(s) listed below. All rights reserved.
+ Chris Danford
+-----------------------------------------------------------------------------
+*/
+
+#include "MemoryCardDriver.h"
+#include "RageThreads.h"
+
+struct UsbStorageDeviceEx : public UsbStorageDevice
+{
+ UsbStorageDeviceEx() { MakeBlank(); }
+
+ void MakeBlank()
+ {
+ bWriteTestSucceeded = false;
+ }
+
+ bool bWriteTestSucceeded;
+};
+
+class MemoryCardDriverThreaded : public MemoryCardDriver
+{
+public:
+ MemoryCardDriverThreaded();
+ ~MemoryCardDriverThreaded();
+ void StartThread(); // call this in the derived constructor to start the mounting thread
+
+ virtual bool StorageDevicesChanged();
+ virtual void GetStorageDevices( vector& vStorageDevicesOut );
+ virtual bool MountAndTestWrite( UsbStorageDevice* pDevice, CString sMountPoint );
+ static int MountThread_Start( void *p );
+protected:
+ virtual void MountThreadMain() = 0;
+ virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint ) = 0;
+
+ RageThread m_threadMemoryCardMount;
+ bool m_bShutdown;
+
+ vector m_vStorageDevices;
+ bool m_bStorageDevicesChanged;
+ RageMutex m_mutexStorageDevices; // protects the above two
+};
+
+#endif
+
+/*
+ * Copyright (c) 2003 by the person(s) listed below. All rights reserved.
+ * Chris Danford
+ */
diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.cpp b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.cpp
new file mode 100644
index 0000000000..becb99f729
--- /dev/null
+++ b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.cpp
@@ -0,0 +1,128 @@
+#include "global.h"
+#include "MemoryCardDriverThreaded_Windows.h"
+#include "RageUtil.h"
+#include
+#include
+#include "RageFileManager.h"
+#include "RageLog.h"
+#include
+
+MemoryCardDriverThreaded_Windows::MemoryCardDriverThreaded_Windows()
+{
+ StartThread();
+}
+
+typedef const CString& CCStringRef;
+
+bool TestWrite( CCStringRef sDrive )
+{
+ // TODO: Use RageFileDirect here to detect ready state?
+ TCHAR szVolumeNameBuffer[MAX_PATH];
+ DWORD dwVolumeSerialNumber;
+ DWORD dwMaximumComponentLength;
+ DWORD lpFileSystemFlags;
+ TCHAR szFileSystemNameBuffer[MAX_PATH];
+ BOOL bReady = GetVolumeInformation(
+ sDrive,
+ szVolumeNameBuffer,
+ sizeof(szVolumeNameBuffer),
+ &dwVolumeSerialNumber,
+ &dwMaximumComponentLength,
+ &lpFileSystemFlags,
+ szFileSystemNameBuffer,
+ sizeof(szFileSystemNameBuffer) );
+ if( !bReady )
+ return false;
+
+ // Try to write a file.
+ // TODO: Can we use RageFile for this?
+ CString sFile = sDrive + "temp";
+ FILE* fp = fopen( sFile, "w" );
+ if( fp == NULL )
+ return false;
+ fclose( fp );
+ remove( sFile );
+
+ return true;
+}
+
+void MemoryCardDriverThreaded_Windows::MountThreadMain()
+{
+ DWORD dwLastLogicalDrives = 0;
+
+ while( !m_bShutdown )
+ {
+ DWORD dwNewLogicalDrives = ::GetLogicalDrives();
+ if( dwNewLogicalDrives != dwLastLogicalDrives )
+ {
+ vector vNewStorageDevices;
+
+ const int MAX_DRIVES = 26;
+ for( int i=2; iWarn( "Found drive %s", sDrive.c_str() );
+
+ if( GetDriveType(sDrive) == DRIVE_REMOVABLE ) // is a removable drive
+ {
+ UsbStorageDeviceEx usbd;
+ usbd.sOsMountDir = sDrive;
+ usbd.bWriteTestSucceeded = TestWrite( sDrive );
+ vNewStorageDevices.push_back( usbd );
+ }
+ }
+ }
+
+ {
+ LockMut( m_mutexStorageDevices );
+ m_bStorageDevicesChanged = true;
+ m_vStorageDevices = vNewStorageDevices;
+ }
+ }
+ dwLastLogicalDrives = dwNewLogicalDrives;
+
+ ::Sleep( 100 );
+ }
+}
+
+void MemoryCardDriverThreaded_Windows::Mount( UsbStorageDevice* pDevice, CString sMountPoint )
+{
+ ASSERT( !pDevice->sOsMountDir.empty() );
+
+ /* Unmount any previous mounts for this mountpoint. */
+ vector Mounts;
+ FILEMAN->GetLoadedDrivers( Mounts );
+ for( unsigned i = 0; i < Mounts.size(); ++i )
+ {
+ if( Mounts[i].Type.CompareNoCase( "dir" ) )
+ continue; // wrong type
+ if( Mounts[i].Root.CompareNoCase( pDevice->sOsMountDir ) )
+ continue; // wrong root
+ FILEMAN->Unmount( Mounts[i].Type, Mounts[i].Root, Mounts[i].MountPoint );
+ }
+
+ FILEMAN->Mount( "dir", pDevice->sOsMountDir, sMountPoint.c_str() );
+ LOG->Trace( "FILEMAN->Mount %s %s", pDevice->sOsMountDir.c_str(), sMountPoint.c_str() );
+}
+
+void MemoryCardDriverThreaded_Windows::Unmount( UsbStorageDevice* pDevice, CString sMountPoint )
+{
+
+ // nothing to do here...
+}
+
+void MemoryCardDriverThreaded_Windows::Flush( UsbStorageDevice* pDevice )
+{
+ // Do we need anything here? I don't lose data if ejecting
+ // soon after a write. From the activity LED, it looks like
+ // Windows flushes automatically every ~2 seconds. -Chris
+}
+
+/*
+ * Copyright (c) 2003 by the person(s) listed below. All rights reserved.
+ * Chris Danford
+ */
diff --git a/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.h b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.h
new file mode 100644
index 0000000000..92d7ed3764
--- /dev/null
+++ b/stepmania/src/arch/MemoryCard/MemoryCardDriverThreaded_Windows.h
@@ -0,0 +1,23 @@
+#ifndef MemoryCardDriverThreaded_Windows_H
+#define MemoryCardDriverThreaded_Windows_H 1
+
+#include "MemoryCardDriverThreaded.h"
+
+class MemoryCardDriverThreaded_Windows : public MemoryCardDriverThreaded
+{
+public:
+ MemoryCardDriverThreaded_Windows();
+
+ virtual void Unmount( UsbStorageDevice* pDevice, CString sMountPoint );
+ virtual void Flush( UsbStorageDevice* pDevice );
+protected:
+ virtual void MountThreadMain();
+ virtual void Mount( UsbStorageDevice* pDevice, CString sMountPoint );
+};
+
+#endif
+
+/*
+ * Copyright (c) 2003 by the person(s) listed below. All rights reserved.
+ * Chris Danford
+ */
diff --git a/stepmania/src/arch/arch.cpp b/stepmania/src/arch/arch.cpp
index c9dca82e67..2aac17c8ce 100644
--- a/stepmania/src/arch/arch.cpp
+++ b/stepmania/src/arch/arch.cpp
@@ -161,7 +161,7 @@ MemoryCardDriver *MakeMemoryCardDriver()
#ifdef LINUX
ret = new MemoryCardDriver_Linux;
#elif _WINDOWS
- ret = new MemoryCardDriver_Windows;
+ ret = new MemoryCardDriverThreaded_Windows;
#endif
if( !ret )
ret = new MemoryCardDriver_Null;
diff --git a/stepmania/src/arch/arch_Win32.h b/stepmania/src/arch/arch_Win32.h
index d28af2946f..3c18cad9f2 100644
--- a/stepmania/src/arch/arch_Win32.h
+++ b/stepmania/src/arch/arch_Win32.h
@@ -15,7 +15,7 @@
#include "Lights/LightsDriver_Win32Parallel.h"
-#include "MemoryCard/MemoryCardDriver_Windows.h"
+#include "MemoryCard/MemoryCardDriverThreaded_Windows.h"
#define HAVE_FFMPEG
#undef SUPPORT_SDL_INPUT