Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 10509)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -58,7 +58,32 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
+static const TCHAR IPCClassName[] = _T("OpenMPT_IPC_Wnd");
 
+static LRESULT CALLBACK IPCWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+	if(uMsg == WM_COPYDATA)
+	{
+		const auto &copyData = *reinterpret_cast<const COPYDATASTRUCT *>(lParam);
+		size_t remain = copyData.cbData / sizeof(WCHAR);
+		const auto *str = static_cast<const WCHAR *>(copyData.lpData);
+		while(remain > 0)
+		{
+			size_t length = wcsnlen(str, remain);
+			const std::wstring name(str, length);
+			theApp.OpenDocumentFile(mpt::PathString::FromWide(name).AsNative().c_str());
+			// Null terminator between strings
+			if(length < remain)
+				length++;
+			str += length;
+			remain -= length;
+		}
+		return TRUE;
+	}
+	return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+
 /////////////////////////////////////////////////////////////////////////////
 // The one and only CTrackApp object
 
@@ -130,6 +155,7 @@
 class CMPTCommandLineInfo: public CCommandLineInfo
 {
 public:
+	std::vector<mpt::PathString> m_fileNames;
 	bool m_bNoDls = false, m_bNoPlugins = false, m_bNoAssembly = false, m_bNoSysCheck = false, m_bNoWine = false,
 		 m_bPortable = false, m_bNoCrashHandler = false, m_bDebugCrashHandler = false;
 #ifdef ENABLE_TESTS
@@ -139,7 +165,7 @@
 public:
 	void ParseParam(LPCTSTR lpszParam, BOOL bFlag, BOOL bLast) override
 	{
-		if ((lpszParam) && (bFlag))
+		if(lpszParam && bFlag)
 		{
 			if (!lstrcmpi(lpszParam, _T("nologo"))) { m_bShowSplash = FALSE; return; }
 			if (!lstrcmpi(lpszParam, _T("nodls"))) { m_bNoDls = true; return; }
@@ -154,6 +180,10 @@
 #ifdef ENABLE_TESTS
 			if (!lstrcmpi(lpszParam, _T("noTests"))) { m_bNoTests = true; return; }
 #endif
+		} else if(lpszParam && !bFlag)
+		{
+			m_fileNames.push_back(mpt::PathString::FromNative(lpszParam));
+			// return;
 		}
 		CCommandLineInfo::ParseParam(lpszParam, bFlag, bLast);
 	}
@@ -797,7 +827,46 @@
 
 	// Parse command line for standard shell commands, DDE, file open
 	ParseCommandLine(cmdInfo);
-	
+
+	auto ipcWnd = ::FindWindow(IPCClassName, nullptr);
+	if(ipcWnd && !cmdInfo.m_fileNames.empty())
+	{
+		// TODO: Would it be better to send one message per file due to "hang" status of thread?
+		std::wstring filenameW;
+		for(const auto &filename : cmdInfo.m_fileNames)
+		{
+			filenameW += filename.ToWide() + L'\0';
+		}
+		const DWORD size = static_cast<DWORD>(filenameW.size() * sizeof(WCHAR));
+		COPYDATASTRUCT copyData{ 0, size, &filenameW[0] };
+
+		DWORD_PTR result = 0;
+		bool success = ::SendMessageTimeout(ipcWnd, WM_COPYDATA, 0, reinterpret_cast<LPARAM>(&copyData), SMTO_ABORTIFHUNG | SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG, 10000, &result) != 0;
+		if(success && result != 0)
+		{
+			ExitProcess(0);
+		}
+	}
+
+	// Still have to create our own window in case the other process closes...
+	{
+		WNDCLASS ipcWindowClass =
+		{
+			0,
+			IPCWindowProc,
+			0,
+			0,
+			m_hInstance,
+			nullptr,
+			nullptr,
+			nullptr,
+			nullptr,
+			IPCClassName
+		};
+		auto ipcAtom = RegisterClass(&ipcWindowClass);
+		CreateWindow(MAKEINTATOM(ipcAtom), _T("OpenMPT IPC Window"), 0, 0, 0, CW_USEDEFAULT, 0, nullptr, nullptr, m_hInstance, 0);
+	}
+
 	if(IsDebuggerPresent() && cmdInfo.m_bDebugCrashHandler)
 	{
 		ExceptionHandler::useAnyCrashHandler = true;
@@ -1030,6 +1099,7 @@
 		// we do not want to open an empty new one on startup.
 		cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
 	}
+	// TODO handle multiple files (MultiSelectModel = Player)
 	if(!ProcessShellCommand(cmdInfo))
 	{
 		EndWaitCursor();
