alroyso 3 年之前
父節點
當前提交
0a9e3720d5
共有 8 個文件被更改,包括 381 次插入355 次删除
  1. 5 5
      SProxy/CLashConfig.cpp
  2. 302 0
      SProxy/CProcessManager.cpp
  3. 66 0
      SProxy/CProcessManager.h
  4. 0 350
      SProxy/ProcessManager.hpp
  5. 二進制
      SProxy/SProxy.cpp
  6. 2 0
      SProxy/SProxy.vcxproj
  7. 6 0
      SProxy/SProxy.vcxproj.filters
  8. 二進制
      SProxy/stdafx.h

+ 5 - 5
SProxy/CLashConfig.cpp

@@ -95,13 +95,13 @@ BOOL CLashConfig::StartClash()
 	//path_config.Format(L"%s\\%s -d %s -f %s", config.c_str(),CLASHEXE,config.c_str(), run_config.c_str());
 	auto assetsDir = std::filesystem::current_path() / CLASH_ASSETS_DIR_NAME;
 	auto confg_path = CApp::getSingletonPtr()->GetConfigPath() / DSPROXY_CONFIG_INIT_ClASH_NAME;
-	ProcessManager::SetArgs(assetsDir / DSPROXY_EXE_NAME, assetsDir, std::move(confg_path));
+	CProcessManager::getSingletonPtr()->SetArgs(assetsDir / DSPROXY_EXE_NAME, assetsDir, std::move(confg_path));
 
 	/*ProcessManager::SetConfigFile(confg_path / DSPROXY_CONFIG_INIT_ClASH_NAME);*/
 	//m_Asyntask.AddTask(&CLashConfig::ThreadFun_process_Config, this, (LPARAM)NULL);
 
 
-	if (ProcessManager::Start())
+	if (CProcessManager::getSingletonPtr()->Start())
 	{
 		CApp::getSingletonPtr()->SetCLashRuning(true);
 	}
@@ -122,7 +122,7 @@ BOOL CLashConfig::StartClash()
 BOOL CLashConfig::StopClash()
 {
 	m_is_qut = true;
-	ProcessManager::Stop();
+	CProcessManager::getSingletonPtr()->Stop();
 	//char ch[MAX_PATH];
 	//memset(ch, 0, MAX_PATH);
 	//sprintf_s(ch, "ok\n");
@@ -173,11 +173,11 @@ std::vector<YAML::Node> CLashConfig::buildRules()
 void CLashConfig::ThreadFun_process_Config(LPARAM lParam)
 {
 
-	if (ProcessManager::Start())
+	if (CProcessManager::getSingletonPtr()->Start())
 	{
 		CApp::getSingletonPtr()->SetCLashRuning(true);
 
-		HANDLE hClashProcess = ProcessManager::GetClashProcessInfo().hProcess;
+		HANDLE hClashProcess = CProcessManager::getSingletonPtr()->GetClashProcessInfo().hProcess;
 
 		for (size_t i = 0; i < 5; ++i) {
 

+ 302 - 0
SProxy/CProcessManager.cpp

@@ -0,0 +1,302 @@
+#include "stdafx.h"
+#include "CProcessManager.h"
+CProcessManager* SSingleton<CProcessManager>::ms_Singleton = NULL;
+
+CProcessManager::CProcessManager()
+{
+
+}
+
+CProcessManager::~CProcessManager()
+{
+
+}
+
+void CProcessManager::_UpdateClashCmd()
+{
+	_clashCmd.assign(LR"(")");
+	_clashCmd.append(_exePath.filename());
+	_clashCmd.append(LR"(")");
+	if (!_homeDir.empty())
+	{
+		_clashCmd.append(LR"( -d ")");
+		_clashCmd.append(_homeDir);
+		_clashCmd.append(LR"(")");
+	}
+	if (!_configFile.empty())
+	{
+		_clashCmd.append(LR"( -f ")");
+		_clashCmd.append(_configFile);
+		_clashCmd.append(LR"(")");
+	}
+	//if (!_uiDir.empty())
+	//{
+	//	_clashCmd.append(LR"( -ext-ui ")");
+	//	_clashCmd.append(_uiDir);
+	//	_clashCmd.append(LR"(")");
+	//}
+	//if (!_ctlAddr.empty())
+	//{
+	//	_clashCmd.append(LR"( -ext-ctl ")");
+	//	_clashCmd.append(_ctlAddr);
+	//	_clashCmd.append(LR"(")");
+	//}
+
+	//// Override secret even if empty
+	//_clashCmd.append(LR"( -secret ")");
+	//_clashCmd.append(_ctlSecret);
+	//_clashCmd.append(LR"(")");
+}
+
+void CProcessManager::SetInsTanCe(HINSTANCE m) {
+	mInstance = m;
+}
+
+ void CProcessManager::SetArgs(std::filesystem::path exePath, std::filesystem::path homeDir, std::filesystem::path cconfigFile)
+{
+	_exePath = exePath;
+	_homeDir = homeDir;
+	_configFile = cconfigFile;
+	_UpdateClashCmd();
+}
+
+ void CProcessManager::SetConfigFile(std::filesystem::path configFile)
+{
+	_configFile = configFile;
+	_UpdateClashCmd();
+}
+
+ bool CProcessManager::Start()
+{
+	if (_state != State::Stop)
+		return false;
+
+	try
+	{
+		_hJob.reset(CreateJobObjectW(nullptr, nullptr));
+		THROW_LAST_ERROR_IF_NULL(_hJob);
+		JOBOBJECT_BASIC_LIMIT_INFORMATION bli;
+		bli.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+		JOBOBJECT_EXTENDED_LIMIT_INFORMATION eli;
+		eli.BasicLimitInformation = bli;
+		THROW_IF_WIN32_BOOL_FALSE(SetInformationJobObject(_hJob.get(), JobObjectExtendedLimitInformation, &eli, sizeof(eli)));
+
+		wchar_t objName[objNameSize + 1] = OBJPREFIX;
+		GUID guid = {};
+		THROW_IF_FAILED(CoCreateGuid(&guid));
+		THROW_HR_IF(E_OUTOFMEMORY, StringFromGUID2(guid, objName + prefixSize, guidSize) != guidSize);
+ 
+		size_t size = (std::max)((_exePath.native().size() + 1) + (_clashCmd.size() + 1) * sizeof(wchar_t), sizeof(ProcessInfo));
+
+		objName[objNameSize - 1] = L'F';
+		wil::unique_handle hFileMapping(CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, static_cast<DWORD>(size), objName));
+		THROW_LAST_ERROR_IF_NULL(hFileMapping);
+		auto error = GetLastError();
+		if (error == ERROR_ALREADY_EXISTS) THROW_WIN32(error);
+
+		wil::unique_mapview_ptr<wchar_t> buffer(reinterpret_cast<wchar_t*>(MapViewOfFile(hFileMapping.get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0)));
+		THROW_LAST_ERROR_IF_NULL(buffer);
+
+
+		objName[objNameSize - 1] = L'E';
+		wil::unique_handle hEvent(CreateEventW(nullptr, FALSE, FALSE, objName));
+		THROW_LAST_ERROR_IF_NULL(hEvent);
+		error = GetLastError();
+		if (error == ERROR_ALREADY_EXISTS) THROW_WIN32(error);
+
+		auto exePathPtr = buffer.get();
+		size_t i = _exePath.native().copy(exePathPtr, std::filesystem::path::string_type::npos);
+		exePathPtr[i] = 0;
+
+		auto cmdPtr = buffer.get() + i + 1;
+		i = _clashCmd.copy(cmdPtr, std::wstring::npos);
+		cmdPtr[i] = 0;
+
+
+		auto selfPath = GetModuleFsPath(mInstance);
+		auto guidStr = objName + prefixSize;
+		std::wstring cmd(LR"(")");
+		cmd.append(selfPath);
+		cmd.append(LR"(" --pm=)");
+		cmd.append(guidStr, guidSize - 1);
+
+		{
+			// Disable Windows Error Reporting for subprocess
+			auto lastErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+			auto restoreErrorMode = wil::scope_exit([=]() { // Restore error mode after CreateProcessW
+				SetErrorMode(lastErrorMode);
+				});
+			wil::unique_cotaskmem_string appId;
+			THROW_IF_FAILED(GetCurrentProcessExplicitAppUserModelID(&appId));
+
+			/*wil::unique_cotaskmem_string appId;
+			THROW_IF_FAILED(GetCurrentProcessExplicitAppUserModelID(&appId));*/
+			/*STARTUPINFOW si = {
+			.cb = sizeof(si),
+			.lpTitle = appId.get(),
+			.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_PREVENTPINNING | STARTF_TITLEISAPPID | STARTF_USESHOWWINDOW,
+			.wShowWindow = SW_HIDE
+			};*/
+
+			STARTUPINFOW si;
+			ZeroMemory(&si, sizeof(si));
+			si.cb = sizeof(si);
+			si.lpTitle = appId.get();
+			si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_PREVENTPINNING | STARTF_TITLEISAPPID | STARTF_USESHOWWINDOW;
+			si.wShowWindow = SW_HIDE;
+			THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(selfPath.c_str(), cmd.data(), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &_subProcInfo));
+		}
+
+		// Ensure process in job before start
+		THROW_IF_WIN32_BOOL_FALSE(AssignProcessToJobObject(_hJob.get(), _subProcInfo.hProcess));
+		THROW_LAST_ERROR_IF(ResumeThread(_subProcInfo.hThread) == static_cast<DWORD>(-1));
+
+		HANDLE handles[] = { hEvent.get(), _subProcInfo.hProcess };
+		auto ret = WaitForMultipleObjects(static_cast<DWORD>(std::size(handles)), handles, FALSE, INFINITE);
+		error = ERROR_TIMEOUT;
+
+		switch (ret)
+		{
+		case WAIT_OBJECT_0: // Event signaled, clash process started suspended
+		{
+			auto info = reinterpret_cast<ProcessInfo*>(buffer.get());
+			_clashProcInfo.dwProcessId = info->processId;
+			_clashProcInfo.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _clashProcInfo.dwProcessId);
+			THROW_LAST_ERROR_IF_NULL(_clashProcInfo.hProcess);
+
+			_clashProcInfo.dwThreadId = info->threadId;
+			_clashProcInfo.hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, _clashProcInfo.dwThreadId);
+			THROW_LAST_ERROR_IF_NULL(_clashProcInfo.hThread);
+
+			_hWndConsole = info->hWndConsole;
+		}
+		break;
+		case WAIT_OBJECT_0 + 1: // Sub process exited before event signaled
+		{
+			DWORD exitCode;
+			THROW_IF_WIN32_BOOL_FALSE(GetExitCodeProcess(_subProcInfo.hProcess, &exitCode));
+			HRESULT hr = static_cast<HRESULT>(exitCode); // Treat exit code as hresult
+			if (SUCCEEDED(hr)) hr = E_UNEXPECTED;
+			THROW_HR(hr);
+		}
+		return false;
+		case WAIT_FAILED:
+			error = GetLastError();
+			[[fallthrough]];
+		case WAIT_TIMEOUT:
+			THROW_WIN32(error);
+			return false;
+		}
+		_hEvent = std::move(hEvent);
+		ResumeThread(_clashProcInfo.hThread);
+	}
+	catch (...)
+	{
+		_hJob.reset();
+		LOG_CAUGHT_EXCEPTION();
+		return false;
+	}
+	_state = State::Running;
+	return true;
+}
+
+ void CProcessManager::Stop()
+{
+	if (_state != State::Stop)
+	{
+		_state = State::Stop;
+		_hJob.reset();
+		_subProcInfo.reset();
+		_clashProcInfo.reset();
+		_hWndConsole = nullptr;
+		_hEvent.reset();
+	}
+}
+
+ void CProcessManager::SendStopSignal()
+{
+	if (_state == State::Running)
+	{
+		_state = State::WaitStop;
+		SetEvent(_hEvent.get());
+	}
+}
+
+ int CProcessManager::SubProcess(std::wstring_view guid)
+{
+	try
+	{
+		wchar_t objName[objNameSize + 1] = OBJPREFIX;
+		size_t i = guid.copy(objName + prefixSize, guidSize - 1);
+		objName[prefixSize + i] = L'F';
+
+		wil::unique_handle hFileMapping(OpenFileMappingW(FILE_MAP_WRITE | FILE_MAP_READ, FALSE, objName));
+		THROW_LAST_ERROR_IF_NULL(hFileMapping);
+
+		wil::unique_mapview_ptr<wchar_t> buffer(reinterpret_cast<wchar_t*>(MapViewOfFile(hFileMapping.get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0)));
+		THROW_LAST_ERROR_IF_NULL(buffer);
+
+		objName[prefixSize + i] = L'E';
+		wil::unique_handle hEvent(OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, objName));
+		THROW_LAST_ERROR_IF_NULL(hEvent);
+
+		THROW_IF_WIN32_BOOL_FALSE(AllocConsole());
+		HWND hWndConsole = ::GetConsoleWindow();
+		THROW_LAST_ERROR_IF_NULL(hWndConsole);
+		ShowWindow(hWndConsole, SW_HIDE);
+
+		auto exePath = buffer.get();
+		auto clashCmd = buffer.get() + wcslen(exePath) + 1;
+
+		STARTUPINFOW si;
+		si.cb = sizeof(si);
+		wil::unique_process_information procInfo;
+		THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(exePath, clashCmd, nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &procInfo));
+
+		auto info = reinterpret_cast<ProcessInfo*>(buffer.get());
+		/**info = {
+		.processId = procInfo.dwProcessId,
+		.threadId = procInfo.dwThreadId,
+		.hWndConsole = hWndConsole
+		};*/
+
+		info->processId = procInfo.dwProcessId;
+		info->threadId = procInfo.dwThreadId;
+		info->hWndConsole = hWndConsole;
+
+
+		SetConsoleCtrlHandler(nullptr, TRUE); // Ignores Ctrl+C
+
+		THROW_IF_WIN32_BOOL_FALSE(SetEvent(hEvent.get()));
+
+		while (true)
+		{
+			HANDLE handles[] = { hEvent.get(), procInfo.hProcess };
+			auto ret = WaitForMultipleObjects(static_cast<DWORD>(std::size(handles)), handles, FALSE, INFINITE);
+			if (ret == WAIT_OBJECT_0) // Event signaled
+			{
+				GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+			}
+			else if (ret == WAIT_OBJECT_0 + 1) // Clash process exited
+			{
+				break;
+			}
+			else if (ret == WAIT_FAILED)
+			{
+				THROW_LAST_ERROR();
+			}
+			else if (ret == WAIT_TIMEOUT)
+			{
+				THROW_WIN32(ERROR_TIMEOUT);
+			}
+		}
+
+		const std::wstring_view msg = (
+			L"\n"
+			L"[Process completed]\n");
+		THROW_IF_WIN32_BOOL_FALSE(WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg.data(), static_cast<DWORD>(msg.size()), nullptr, nullptr));
+		static_cast<void>(_getch());
+	}
+	CATCH_RETURN();
+	return S_OK;
+}

+ 66 - 0
SProxy/CProcessManager.h

@@ -0,0 +1,66 @@
+#pragma once
+#define OBJPREFIX LR"(Local\)"
+constexpr size_t guidSize = std::size(L"{00000000-0000-0000-0000-000000000000}"); // including the null terminator
+constexpr size_t prefixSize = std::size(OBJPREFIX) - 1;
+constexpr size_t objNameSize = prefixSize + guidSize;
+
+struct ProcessInfo
+{
+	DWORD processId;
+	DWORD threadId;
+	HWND hWndConsole;
+};
+
+
+class CProcessManager : public SSingleton<CProcessManager>
+{
+public:
+	enum struct State
+	{
+		Stop,
+		Running,
+		WaitStop
+	};
+
+	CProcessManager();
+	~CProcessManager();
+
+
+	void _UpdateClashCmd();
+
+	void SetInsTanCe(HINSTANCE m);
+
+	void SetArgs(std::filesystem::path exePath, std::filesystem::path homeDir, std::filesystem::path cconfigFile);
+
+	void SetConfigFile(std::filesystem::path configFile);
+
+
+	inline State IsRunning() { return _state; }
+	inline const PROCESS_INFORMATION& GetSubProcessInfo() { return _subProcInfo; }
+	inline const PROCESS_INFORMATION& GetClashProcessInfo() { return _clashProcInfo; }
+	inline HWND GetConsoleWindow() { return _hWndConsole; }
+
+
+	bool Start();
+
+	void Stop();
+
+	void SendStopSignal();
+
+
+	int SubProcess(std::wstring_view guid);
+
+private:
+	State _state = State::Stop;
+	std::filesystem::path _exePath;
+	std::filesystem::path _homeDir;
+	std::filesystem::path _configFile;
+	std::wstring _ctlAddr, _ctlSecret, _clashCmd;
+	wil::unique_handle _hJob;
+	wil::unique_process_information _subProcInfo, _clashProcInfo;
+	HWND _hWndConsole = nullptr;
+	wil::unique_handle _hEvent;
+	HINSTANCE mInstance;
+
+};
+

+ 0 - 350
SProxy/ProcessManager.hpp

@@ -1,350 +0,0 @@
-#pragma once
-# ifndef PROCESS_H
-# define PROCESS_H
-
-
-#define OBJPREFIX LR"(Local\)"
-constexpr size_t guidSize = std::size(L"{00000000-0000-0000-0000-000000000000}"); // including the null terminator
-constexpr size_t prefixSize = std::size(OBJPREFIX) - 1;
-constexpr size_t objNameSize = prefixSize + guidSize;
-
-struct ProcessInfo
-{
-	DWORD processId;
-	DWORD threadId;
-	HWND hWndConsole;
-};
-
-namespace ProcessManager
-{
-	enum struct State
-	{
-		Stop,
-		Running,
-		WaitStop
-	};
-
-	namespace {
-		State _state = State::Stop;
-		std::filesystem::path _exePath;
-		std::filesystem::path _homeDir;
-		std::filesystem::path _configFile;
-		std::wstring _ctlAddr, _ctlSecret, _clashCmd;
-		wil::unique_handle _hJob;
-		wil::unique_process_information _subProcInfo, _clashProcInfo;
-		HWND _hWndConsole = nullptr;
-		wil::unique_handle _hEvent;
-		HINSTANCE mInstance;
- 
-		void _UpdateClashCmd()
-		{
-			_clashCmd.assign(LR"(")");
-			_clashCmd.append(_exePath.filename());
-			_clashCmd.append(LR"(")");
-			if (!_homeDir.empty())
-			{
-				_clashCmd.append(LR"( -d ")");
-				_clashCmd.append(_homeDir);
-				_clashCmd.append(LR"(")");
-			}
-			if (!_configFile.empty())
-			{
-				_clashCmd.append(LR"( -f ")");
-				_clashCmd.append(_configFile);
-				_clashCmd.append(LR"(")");
-			}
-			//if (!_uiDir.empty())
-			//{
-			//	_clashCmd.append(LR"( -ext-ui ")");
-			//	_clashCmd.append(_uiDir);
-			//	_clashCmd.append(LR"(")");
-			//}
-			//if (!_ctlAddr.empty())
-			//{
-			//	_clashCmd.append(LR"( -ext-ctl ")");
-			//	_clashCmd.append(_ctlAddr);
-			//	_clashCmd.append(LR"(")");
-			//}
-
-			//// Override secret even if empty
-			//_clashCmd.append(LR"( -secret ")");
-			//_clashCmd.append(_ctlSecret);
-			//_clashCmd.append(LR"(")");
-		}
-
-	}
-
-	inline void SetInsTanCe(HINSTANCE m) {
-		mInstance = m;
-	}
-
-	 void SetArgs(std::filesystem::path exePath, std::filesystem::path homeDir, std::filesystem::path cconfigFile)
-	{
-
-	 
-
-		_exePath = exePath;
-		_homeDir = homeDir;
-		_configFile = cconfigFile;
-		//_uiDir = "";
-		//_ctlAddr = L"";
-		//_ctlSecret = L"";
-
-		_UpdateClashCmd();
-	}
-
-	 void SetConfigFile(std::filesystem::path configFile)
-	{
-		_configFile = configFile;
-
-		_UpdateClashCmd();
-	}
-
-	inline State IsRunning() { return _state; }
-	inline const PROCESS_INFORMATION& GetSubProcessInfo() { return _subProcInfo; }
-	inline const PROCESS_INFORMATION& GetClashProcessInfo() { return _clashProcInfo; }
-	inline HWND GetConsoleWindow() { return _hWndConsole; }
-
-	inline bool Start()
-	{
-		if (_state != State::Stop)
-			return false;
-
-		try
-		{
-			_hJob.reset(CreateJobObjectW(nullptr, nullptr));
-			THROW_LAST_ERROR_IF_NULL(_hJob);
-			JOBOBJECT_BASIC_LIMIT_INFORMATION bli;
-			bli.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
-			JOBOBJECT_EXTENDED_LIMIT_INFORMATION eli;
-			eli.BasicLimitInformation = bli;
-			THROW_IF_WIN32_BOOL_FALSE(SetInformationJobObject(_hJob.get(), JobObjectExtendedLimitInformation, &eli, sizeof(eli)));
-			
-			wchar_t objName[objNameSize + 1] = OBJPREFIX;
-			GUID guid = {};
-			THROW_IF_FAILED(CoCreateGuid(&guid));
-			THROW_HR_IF(E_OUTOFMEMORY, StringFromGUID2(guid, objName + prefixSize, guidSize) != guidSize);
-
-			size_t s = (_exePath.native().size() + 1) + (_clashCmd.size() + 1) * sizeof(wchar_t);
-			size_t l = sizeof(ProcessInfo);
-			size_t size = max(s, l);
-
-			objName[objNameSize - 1] = L'F';
-			wil::unique_handle hFileMapping(CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, static_cast<DWORD>(size), objName));
-			THROW_LAST_ERROR_IF_NULL(hFileMapping);
-			auto error = GetLastError();
-			if (error == ERROR_ALREADY_EXISTS) THROW_WIN32(error);
-
-			wil::unique_mapview_ptr<wchar_t> buffer(reinterpret_cast<wchar_t*>(MapViewOfFile(hFileMapping.get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0)));
-			THROW_LAST_ERROR_IF_NULL(buffer);
-
-
-			objName[objNameSize - 1] = L'E';
-			wil::unique_handle hEvent(CreateEventW(nullptr, FALSE, FALSE, objName));
-			THROW_LAST_ERROR_IF_NULL(hEvent);
-			error = GetLastError();
-			if (error == ERROR_ALREADY_EXISTS) THROW_WIN32(error);
-
-			auto exePathPtr = buffer.get();
-			size_t i = _exePath.native().copy(exePathPtr, std::filesystem::path::string_type::npos);
-			exePathPtr[i] = 0;
-
-			auto cmdPtr = buffer.get() + i + 1;
-			i = _clashCmd.copy(cmdPtr, std::wstring::npos);
-			cmdPtr[i] = 0;
-
-
-			auto selfPath = GetModuleFsPath(mInstance);
-			auto guidStr = objName + prefixSize;
-			std::wstring cmd(LR"(")");
-			cmd.append(selfPath);
-			cmd.append(LR"(" --pm=)");
-			cmd.append(guidStr, guidSize - 1);
-
-			{
-				// Disable Windows Error Reporting for subprocess
-				auto lastErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
-				auto restoreErrorMode = wil::scope_exit([=]() { // Restore error mode after CreateProcessW
-					SetErrorMode(lastErrorMode);
-					});
-				wil::unique_cotaskmem_string appId;
-				THROW_IF_FAILED(GetCurrentProcessExplicitAppUserModelID(&appId));
-
-				/*wil::unique_cotaskmem_string appId;
-				THROW_IF_FAILED(GetCurrentProcessExplicitAppUserModelID(&appId));*/
-				/*STARTUPINFOW si = {
-					.cb = sizeof(si),
-					.lpTitle = appId.get(),
-					.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_PREVENTPINNING | STARTF_TITLEISAPPID | STARTF_USESHOWWINDOW,
-					.wShowWindow = SW_HIDE
-				};*/
-
-				STARTUPINFOW si;
-				si.cb = sizeof(si);
-				si.lpTitle = appId.get();
-				si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_PREVENTPINNING | STARTF_TITLEISAPPID | STARTF_USESHOWWINDOW;
-				si.wShowWindow = SW_HIDE;
-				THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(selfPath.c_str(), cmd.data(), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &_subProcInfo));
-			}
-
-			// Ensure process in job before start
-			THROW_IF_WIN32_BOOL_FALSE(AssignProcessToJobObject(_hJob.get(), _subProcInfo.hProcess));
-			THROW_LAST_ERROR_IF(ResumeThread(_subProcInfo.hThread) == static_cast<DWORD>(-1));
-
-			HANDLE handles[] = { hEvent.get(), _subProcInfo.hProcess };
-			auto ret = WaitForMultipleObjects(static_cast<DWORD>(std::size(handles)), handles, FALSE, INFINITE);
-			error = ERROR_TIMEOUT;
-
-			switch (ret)
-			{
-			case WAIT_OBJECT_0: // Event signaled, clash process started suspended
-			{
-				auto info = reinterpret_cast<ProcessInfo*>(buffer.get());
-				_clashProcInfo.dwProcessId = info->processId;
-				_clashProcInfo.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _clashProcInfo.dwProcessId);
-				THROW_LAST_ERROR_IF_NULL(_clashProcInfo.hProcess);
-
-				_clashProcInfo.dwThreadId = info->threadId;
-				_clashProcInfo.hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, _clashProcInfo.dwThreadId);
-				THROW_LAST_ERROR_IF_NULL(_clashProcInfo.hThread);
-
-				_hWndConsole = info->hWndConsole;
-			}
-			break;
-			case WAIT_OBJECT_0 + 1: // Sub process exited before event signaled
-			{
-				DWORD exitCode;
-				THROW_IF_WIN32_BOOL_FALSE(GetExitCodeProcess(_subProcInfo.hProcess, &exitCode));
-				HRESULT hr = static_cast<HRESULT>(exitCode); // Treat exit code as hresult
-				if (SUCCEEDED(hr)) hr = E_UNEXPECTED;
-				THROW_HR(hr);
-			}
-			return false;
-			case WAIT_FAILED:
-				error = GetLastError();
-				[[fallthrough]];
-			case WAIT_TIMEOUT:
-				THROW_WIN32(error);
-				return false;
-			}
-			_hEvent = std::move(hEvent);
-			ResumeThread(_clashProcInfo.hThread);
-		}
-		catch (...)
-		{
-			_hJob.reset();
-			LOG_CAUGHT_EXCEPTION();
-			return false;
-		}
-		_state = State::Running;
-		return true;
-	}
-
-
-	inline void Stop()
-	{
-		if (_state != State::Stop)
-		{
-			_state = State::Stop;
-			_hJob.reset();
-			_subProcInfo.reset();
-			_clashProcInfo.reset();
-			_hWndConsole = nullptr;
-			_hEvent.reset();
-		}
-	}
-
-	inline void SendStopSignal()
-	{
-		if (_state == State::Running)
-		{
-			_state = State::WaitStop;
-			SetEvent(_hEvent.get());
-		}
-	}
-
-
-	inline int SubProcess(std::wstring_view guid)
-	{
-		try
-		{
-			wchar_t objName[objNameSize + 1] = OBJPREFIX;
-			size_t i = guid.copy(objName + prefixSize, guidSize - 1);
-			objName[prefixSize + i] = L'F';
-
-			wil::unique_handle hFileMapping(OpenFileMappingW(FILE_MAP_WRITE | FILE_MAP_READ, FALSE, objName));
-			THROW_LAST_ERROR_IF_NULL(hFileMapping);
-
-			wil::unique_mapview_ptr<wchar_t> buffer(reinterpret_cast<wchar_t*>(MapViewOfFile(hFileMapping.get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0)));
-			THROW_LAST_ERROR_IF_NULL(buffer);
-
-			objName[prefixSize + i] = L'E';
-			wil::unique_handle hEvent(OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, objName));
-			THROW_LAST_ERROR_IF_NULL(hEvent);
-
-			THROW_IF_WIN32_BOOL_FALSE(AllocConsole());
-			HWND hWndConsole = ::GetConsoleWindow();
-			THROW_LAST_ERROR_IF_NULL(hWndConsole);
-			ShowWindow(hWndConsole, SW_HIDE);
-
-			auto exePath = buffer.get();
-			auto clashCmd = buffer.get() + wcslen(exePath) + 1;
-		 
-			STARTUPINFOW si;
-			si.cb = sizeof(si);
-			wil::unique_process_information procInfo;
-			THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(exePath, clashCmd, nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &procInfo));
-
-			auto info = reinterpret_cast<ProcessInfo*>(buffer.get());
-			/**info = {
-				.processId = procInfo.dwProcessId,
-				.threadId = procInfo.dwThreadId,
-				.hWndConsole = hWndConsole
-			};*/
-
-			info->processId = procInfo.dwProcessId;
-			info->threadId = procInfo.dwThreadId;
-			info->hWndConsole = hWndConsole;
-
-
-			SetConsoleCtrlHandler(nullptr, TRUE); // Ignores Ctrl+C
-
-			THROW_IF_WIN32_BOOL_FALSE(SetEvent(hEvent.get()));
-
-			while (true)
-			{
-				HANDLE handles[] = { hEvent.get(), procInfo.hProcess };
-				auto ret = WaitForMultipleObjects(static_cast<DWORD>(std::size(handles)), handles, FALSE, INFINITE);
-				if (ret == WAIT_OBJECT_0) // Event signaled
-				{
-					GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
-				}
-				else if (ret == WAIT_OBJECT_0 + 1) // Clash process exited
-				{
-					break;
-				}
-				else if (ret == WAIT_FAILED)
-				{
-					THROW_LAST_ERROR();
-				}
-				else if (ret == WAIT_TIMEOUT)
-				{
-					THROW_WIN32(ERROR_TIMEOUT);
-				}
-			}
-
-			const std::wstring_view msg = (
-				L"\n"
-				L"[Process completed]\n");
-			THROW_IF_WIN32_BOOL_FALSE(WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg.data(), static_cast<DWORD>(msg.size()), nullptr, nullptr));
-			static_cast<void>(_getch());
-		}
-		CATCH_RETURN();
-		return S_OK;
-	}
-}
-
-
-#undef OBJPREFIX
-
-# endif

二進制
SProxy/SProxy.cpp


+ 2 - 0
SProxy/SProxy.vcxproj

@@ -196,6 +196,7 @@
     <ClCompile Include="CManageNetWork.cpp" />
     <ClCompile Include="CNetWork.cpp" />
     <ClCompile Include="CProcess.cpp" />
+    <ClCompile Include="CProcessManager.cpp" />
     <ClCompile Include="CTool.cpp" />
     <ClCompile Include="CUserInfo.cpp" />
     <ClCompile Include="FileOperate.cpp" />
@@ -227,6 +228,7 @@
     <ClInclude Include="CNetWork.h" />
     <ClInclude Include="comm.h" />
     <ClInclude Include="CProcess.h" />
+    <ClInclude Include="CProcessManager.h" />
     <ClInclude Include="CTool.h" />
     <ClInclude Include="CUserInfo.h" />
     <ClInclude Include="event.h" />

+ 6 - 0
SProxy/SProxy.vcxproj.filters

@@ -98,6 +98,9 @@
     <ClCompile Include="Logger.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="CProcessManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="SProxy.rc">
@@ -180,6 +183,9 @@
     <ClInclude Include="Util.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="CProcessManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\soui_res.rc2">

二進制
SProxy/stdafx.h