diff --git a/3rdparty/wxwidgets3.0/include/wx/string.h b/3rdparty/wxwidgets3.0/include/wx/string.h
index ddd5fe0081..4f7b99cc0b 100644
--- a/3rdparty/wxwidgets3.0/include/wx/string.h
+++ b/3rdparty/wxwidgets3.0/include/wx/string.h
@@ -1621,13 +1621,17 @@ public:
     // messages for the code which relies on implicit conversion to char* in
     // STL build
 #if !wxUSE_STD_STRING_CONV_IN_WXSTRING
+#ifndef _WIN32 // PCSX2: std::string conversion removal
     operator const char*() const { return c_str(); }
+#endif
     operator const wchar_t*() const { return c_str(); }
 
+#ifndef _WIN32 // PCSX2: std::string conversion removal
     // implicit conversion to untyped pointer for compatibility with previous
     // wxWidgets versions: this is the same as conversion to const char * so it
     // may fail!
     operator const void*() const { return c_str(); }
+#endif
 #endif // !wxUSE_STD_STRING_CONV_IN_WXSTRING
 
     // identical to c_str(), for MFC compatibility
diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp
index 27d28558fb..6aff15763b 100644
--- a/pcsx2/GS/GS.cpp
+++ b/pcsx2/GS/GS.cpp
@@ -1365,7 +1365,7 @@ void GSApp::SetConfigDir()
 	// core settings aren't populated yet, thus we do populate it if needed either when
 	// opening GS settings or init -- govanify
 	wxString iniName(L"GS.ini");
-	m_ini = EmuFolders::Settings.Combine(iniName).GetFullPath();
+	m_ini = EmuFolders::Settings.Combine(iniName).GetFullPath().ToUTF8();
 }
 
 std::string GSApp::GetConfigS(const char* entry)
diff --git a/pcsx2/GS/Window/GSwxDialog.cpp b/pcsx2/GS/Window/GSwxDialog.cpp
index b4d3c6853f..4032bb916a 100644
--- a/pcsx2/GS/Window/GSwxDialog.cpp
+++ b/pcsx2/GS/Window/GSwxDialog.cpp
@@ -235,7 +235,7 @@ void GSUIElementHolder::Save()
 				break;
 			case UIElem::Type::File:
 			case UIElem::Type::Directory:
-				theApp.SetConfig(elem.config, static_cast<wxFileDirPickerCtrlBase*>(elem.control)->GetPath());
+				theApp.SetConfig(elem.config, static_cast<wxFileDirPickerCtrlBase*>(elem.control)->GetPath().ToUTF8());
 				break;
 		}
 	}
diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp
index c064108ee1..b3a2814d72 100644
--- a/pcsx2/GameDatabase.cpp
+++ b/pcsx2/GameDatabase.cpp
@@ -103,7 +103,7 @@ GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::str
 			bool fixValidated = false;
 			for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++)
 			{
-				std::string validFix = fmt::format("{}Hack", wxString(EnumToString(id)));
+				std::string validFix = fmt::format("{}Hack", wxString(EnumToString(id)).ToUTF8());
 				if (validFix == fix)
 				{
 					fixValidated = true;
@@ -129,7 +129,7 @@ GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::str
 				bool speedHackValidated = false;
 				for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++)
 				{
-					std::string validSpeedHack = fmt::format("{}SpeedHack", wxString(EnumToString(id)));
+					std::string validSpeedHack = fmt::format("{}SpeedHack", wxString(EnumToString(id)).ToUTF8());
 					if (validSpeedHack == speedHack)
 					{
 						speedHackValidated = true;
diff --git a/pcsx2/PAD/Windows/PADConfig.cpp b/pcsx2/PAD/Windows/PADConfig.cpp
index 9f0b95f01b..5b9163b516 100644
--- a/pcsx2/PAD/Windows/PADConfig.cpp
+++ b/pcsx2/PAD/Windows/PADConfig.cpp
@@ -337,7 +337,7 @@ void PADsetSettingsDir(const char* dir)
 
 	//uint targlen = MultiByteToWideChar(CP_ACP, 0, dir, -1, NULL, 0);
 	wxString iniName = "PAD.ini";
-	MultiByteToWideChar(CP_UTF8, 0, std::string(EmuFolders::Settings.Combine(iniName).GetFullPath()).c_str(), -1, iniFileUSB, MAX_PATH * 2);
+	StrCpyNW(iniFileUSB, EmuFolders::Settings.Combine(iniName).GetFullPath(), std::size(iniFileUSB));
 
 	createIniDir = false;
 
diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp
index f4a57926a9..a6268f5237 100644
--- a/pcsx2/Patch.cpp
+++ b/pcsx2/Patch.cpp
@@ -134,7 +134,7 @@ int LoadPatchesFromGamesDB(const wxString& crc, const GameDatabaseSchema::GameEn
 	if (game.isValid)
 	{
 		GameDatabaseSchema::Patch patch;
-		bool patchFound = game.findPatch(std::string(crc), patch);
+		bool patchFound = game.findPatch(std::string(crc.ToUTF8()), patch);
 		if (patchFound && patch.patchLines.size() > 0)
 		{
 			for (auto line : patch.patchLines)
diff --git a/pcsx2/Recording/InputRecording.cpp b/pcsx2/Recording/InputRecording.cpp
index 6956cda346..18ed6a6c03 100644
--- a/pcsx2/Recording/InputRecording.cpp
+++ b/pcsx2/Recording/InputRecording.cpp
@@ -286,7 +286,7 @@ void InputRecording::SetupInitialState(u32 newStartingFrame)
 	if (state != InputRecordingMode::Replaying)
 	{
 		inputRec::log("Started new input recording");
-		inputRec::consoleLog(fmt::format("Filename {}", std::string(inputRecordingData.GetFilename())));
+		inputRec::consoleLog(fmt::format("Filename {}", inputRecordingData.GetFilename().ToUTF8()));
 		SetToRecordMode();
 	}
 	else
@@ -298,7 +298,7 @@ void InputRecording::SetupInitialState(u32 newStartingFrame)
 
 		incrementUndo = true;
 		inputRec::log("Replaying input recording");
-		inputRec::consoleMultiLog({fmt::format("File: {}", std::string(inputRecordingData.GetFilename())),
+		inputRec::consoleMultiLog({fmt::format("File: {}", inputRecordingData.GetFilename().ToUTF8()),
 								   fmt::format("PCSX2 Version Used: {}", std::string(inputRecordingData.GetHeader().emu)),
 								   fmt::format("Recording File Version: {}", inputRecordingData.GetHeader().version),
 								   fmt::format("Associated Game Name or ISO Filename: {}", std::string(inputRecordingData.GetHeader().gameName)),
@@ -317,7 +317,7 @@ void InputRecording::SetupInitialState(u32 newStartingFrame)
 
 void InputRecording::FailedSavestate()
 {
-	inputRec::consoleLog(fmt::format("{} is not compatible with this version of PCSX2", savestate));
+	inputRec::consoleLog(fmt::format("{} is not compatible with this version of PCSX2", savestate.ToUTF8()));
 	inputRec::consoleLog(fmt::format("Original PCSX2 version used: {}", inputRecordingData.GetHeader().emu));
 	inputRecordingData.Close();
 	initialLoad = false;
@@ -388,14 +388,14 @@ bool InputRecording::Play(wxWindow* parent, wxString filename)
 										 L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
 			if (loadStateDialog.ShowModal() == wxID_CANCEL)
 			{
-				inputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestate));
+				inputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestate.ToUTF8()));
 				inputRec::log("Savestate load failed");
 				inputRecordingData.Close();
 				return false;
 			}
 
 			savestate = loadStateDialog.GetPath();
-			inputRec::consoleLog(fmt::format("Base savestate set to {}", savestate));
+			inputRec::consoleLog(fmt::format("Base savestate set to {}", savestate.ToUTF8()));
 		}
 		state = InputRecordingMode::Replaying;
 		initialLoad = true;
@@ -421,7 +421,7 @@ void InputRecording::GoToFirstFrame(wxWindow* parent)
 			if (!initiallyPaused)
 				g_InputRecordingControls.PauseImmediately();
 
-			inputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}\n", savestate));
+			inputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}\n", savestate.ToUTF8()));
 			wxFileDialog loadStateDialog(parent, _("Select a savestate to accompany the recording with"), L"", L"",
 										 L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
 			int result = loadStateDialog.ShowModal();
@@ -434,7 +434,7 @@ void InputRecording::GoToFirstFrame(wxWindow* parent)
 				return;
 			}
 			savestate = loadStateDialog.GetPath();
-			inputRec::consoleLog(fmt::format ("Base savestate swapped to {}", savestate));
+			inputRec::consoleLog(fmt::format ("Base savestate swapped to {}", savestate.ToUTF8()));
 		}
 		StateCopy_LoadFromFile(savestate);
 	}
@@ -454,7 +454,7 @@ wxString InputRecording::resolveGameName()
 	{
 		if (IGameDatabase* gameDB = AppHost_GetGameDatabase())
 		{
-			GameDatabaseSchema::GameEntry game = gameDB->findGame(std::string(gameKey));
+			GameDatabaseSchema::GameEntry game = gameDB->findGame(std::string(gameKey.ToUTF8()));
 			if (game.isValid)
 			{
 				gameName = fromUTF8(game.name);
diff --git a/pcsx2/SPU2/Wavedump_wav.cpp b/pcsx2/SPU2/Wavedump_wav.cpp
index 6578d0f537..4c40560921 100644
--- a/pcsx2/SPU2/Wavedump_wav.cpp
+++ b/pcsx2/SPU2/Wavedump_wav.cpp
@@ -19,6 +19,7 @@
 #include "WavFile.h"
 #else
 #include "soundtouch/source/SoundStretch/WavFile.h"
+#include "common/StringUtil.h"
 #endif
 
 static WavOutFile* _new_WavOutFile(const char* destfile)
@@ -117,7 +118,11 @@ bool RecordStart(const std::string* filename)
 		ScopedLock lock(WavRecordMutex);
 		safe_delete(m_wavrecord);
 		if (filename)
+#ifdef _WIN32
+			m_wavrecord = new WavOutFile(_wfopen(StringUtil::UTF8StringToWideString(*filename).c_str(), L"wb"), 48000, 16, 2);
+#else
 			m_wavrecord = new WavOutFile(filename->c_str(), 48000, 16, 2);
+#endif
 		else
 			m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
 		WavRecordEnabled = true;
diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp
index 222723c824..1b47ef1f4f 100644
--- a/pcsx2/gui/AppCoreThread.cpp
+++ b/pcsx2/gui/AppCoreThread.cpp
@@ -314,7 +314,7 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
 	// TODO - config - this could be simplified with maps instead of bitfields and enums
 	for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++)
 	{
-		std::string key = fmt::format("{}SpeedHack", wxString(EnumToString(id)));
+		std::string key = fmt::format("{}SpeedHack", wxString(EnumToString(id)).ToUTF8());
 
 		// Gamefixes are already guaranteed to be valid, any invalid ones are dropped
 		if (game.speedHacks.count(key) == 1)
@@ -331,7 +331,7 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
 	// TODO - config - this could be simplified with maps instead of bitfields and enums
 	for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++)
 	{
-		std::string key = fmt::format("{}Hack", wxString(EnumToString(id)));
+		std::string key = fmt::format("{}Hack", wxString(EnumToString(id)).ToUTF8());
 
 		// Gamefixes are already guaranteed to be valid, any invalid ones are dropped
 		if (std::find(game.gameFixes.begin(), game.gameFixes.end(), key) != game.gameFixes.end())
@@ -452,7 +452,7 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
 	{
 		if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
 		{
-			GameDatabaseSchema::GameEntry game = GameDB->findGame(std::string(curGameKey));
+			GameDatabaseSchema::GameEntry game = GameDB->findGame(std::string(curGameKey.ToUTF8()));
 			if (game.isValid)
 			{
 				GameInfo::gameName = fromUTF8(game.name);
diff --git a/pcsx2/gui/Debugger/CtrlMemSearch.cpp b/pcsx2/gui/Debugger/CtrlMemSearch.cpp
index e038faa539..8100a6b5bd 100644
--- a/pcsx2/gui/Debugger/CtrlMemSearch.cpp
+++ b/pcsx2/gui/Debugger/CtrlMemSearch.cpp
@@ -229,7 +229,7 @@ void CtrlMemSearch::Search(wxCommandEvent& evt)
 	wxString searchString = txtSearch->GetValue();
 	if (m_SearchThread->m_type == SEARCHTYPE::STRING)
 	{
-		m_SearchThread->m_value_string = searchString;
+		m_SearchThread->m_value_string = searchString.ToUTF8();
 	}
 	else if (chkHexadecimal->IsChecked())
 	{