chore: use overlapped io for win32 subprocess

This commit is contained in:
dantmnf
2022-09-04 14:37:41 +08:00
parent 87b8f8f032
commit a540cb4b6d
8 changed files with 365 additions and 196 deletions

View File

@@ -73,5 +73,181 @@ std::string asst::utils::from_osstring(const asst::utils::os_string& os_str)
}
std::string asst::utils::callcmd(const std::string& cmdline)
{
static std::atomic<size_t> pipeid {};
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
ASST_AUTO_DEDUCED_ZERO_INIT_START
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
ASST_AUTO_DEDUCED_ZERO_INIT_END
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipe_sec_attr.lpSecurityDescriptor = nullptr;
pipe_sec_attr.bInheritHandle = TRUE;
auto pipename = std::format(L"\\\\.\\pipe\\maa-callcmd-{}-{}", GetCurrentProcessId(), pipeid++);
auto pipe_read =
CreateNamedPipeW(pipename.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, PipeBuffSize, PipeBuffSize, 0, nullptr);
auto pipe_child_write =
CreateFileW(pipename.c_str(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
ASST_AUTO_DEDUCED_ZERO_INIT_START
STARTUPINFOW si = { 0 };
ASST_AUTO_DEDUCED_ZERO_INIT_END
si.cb = sizeof(STARTUPINFOW);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = pipe_child_write;
si.hStdError = pipe_child_write;
ASST_AUTO_DEDUCED_ZERO_INIT_START
PROCESS_INFORMATION pi = { nullptr };
ASST_AUTO_DEDUCED_ZERO_INIT_END
auto cmdline_osstr = asst::utils::to_osstring(cmdline);
BOOL p_ret = CreateProcessW(nullptr, &cmdline_osstr[0], nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr,
&si, &pi);
if (p_ret) {
DWORD read_num = 0;
OVERLAPPED ov { .hEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr) };
bool reading = false;
bool process_running = true;
bool pipe_eof = false;
bool process_signaled = false, pipe_signaled = false;
HANDLE wait_handles[] { pi.hProcess, ov.hEvent };
while (process_running || !pipe_eof) {
if (!pipe_eof && !reading) {
(void)ReadFile(pipe_read, pipe_buffer.get(), PipeBuffSize, nullptr, &ov);
reading = true;
}
DWORD wait_result = WAIT_FAILED;
if (process_running && !pipe_eof) {
wait_result = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
process_signaled = wait_result == WAIT_OBJECT_0;
pipe_signaled = wait_result == WAIT_OBJECT_0 + 1;
}
else if (!pipe_eof) { // process exited, pipe not eof yet
wait_result = WaitForMultipleObjects(1, wait_handles + 1, FALSE, INFINITE);
pipe_signaled = wait_result == WAIT_OBJECT_0;
}
else if (process_running) { // pipe eof, process not exit yet
wait_result = WaitForMultipleObjects(1, wait_handles, FALSE, INFINITE);
process_signaled = wait_result == WAIT_OBJECT_0;
}
if (wait_result == WAIT_FAILED) {
// something bad happened
abort();
}
if (process_signaled) {
// process died, wait for data remaining in pipe
process_running = false;
}
if (pipe_signaled) {
reading = false;
// pipe read
if (GetOverlappedResult(pipe_read, &ov, &read_num, TRUE)) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
}
else {
if (GetLastError() == ERROR_HANDLE_EOF) {
pipe_eof = true;
}
}
}
};
// fetch data in pipe buffer (if any)
//if (reading) {
// if (GetOverlappedResult(pipe_read, &ov, &read_num, FALSE)) {
// pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
// }
// else {
// CancelIo(pipe_read);
// }
//}
//while (PeekNamedPipe(pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
// ReadFile(pipe_read, pipe_buffer.get(), PipeBuffSize, nullptr, &ov);
// if (GetOverlappedResult(pipe_read, &ov, &read_num, TRUE)) {
// pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
// }
//}
DWORD exit_ret = 255;
GetExitCodeProcess(pi.hProcess, &exit_ret);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(ov.hEvent);
}
CloseHandle(pipe_read);
CloseHandle(pipe_child_write);
return pipe_str;
}
#else
std::string asst::utils::callcmd(const std::string& cmdline)
{
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
constexpr static int PIPE_READ = 0;
constexpr static int PIPE_WRITE = 1;
int pipe_in[2] = { 0 };
int pipe_out[2] = { 0 };
int pipe_in_ret = pipe(pipe_in);
int pipe_out_ret = pipe(pipe_out);
if (pipe_in_ret != 0 || pipe_out_ret != 0) {
return {};
}
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int exit_ret = 0;
int child = fork();
if (child == 0) {
// child process
dup2(pipe_in[PIPE_READ], STDIN_FILENO);
dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
// all these are for use by parent only
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
exit_ret = execlp("sh", "sh", "-c", cmdline.c_str(), nullptr);
exit(exit_ret);
}
else if (child > 0) {
// parent process
// close unused file descriptors, these are for child only
close(pipe_in[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
do {
ssize_t read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
while (read_num > 0) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
};
} while (::waitpid(child, &exit_ret, WNOHANG) == 0);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
}
else {
// failed to create child process
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
}
return pipe_str;
}
#endif

View File

@@ -9,7 +9,7 @@
#include <string>
#ifdef _WIN32
#include <Windows.h>
#include "SafeWindows.h"
#else
#include <ctime>
#include <fcntl.h>
@@ -478,115 +478,7 @@ namespace asst::utils
return str;
}
inline std::string callcmd(const std::string& cmdline)
{
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
#ifdef _WIN32
ASST_AUTO_DEDUCED_ZERO_INIT_START
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
ASST_AUTO_DEDUCED_ZERO_INIT_END
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipe_sec_attr.lpSecurityDescriptor = nullptr;
pipe_sec_attr.bInheritHandle = TRUE;
HANDLE pipe_read = nullptr;
HANDLE pipe_child_write = nullptr;
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, PipeBuffSize);
ASST_AUTO_DEDUCED_ZERO_INIT_START
STARTUPINFOA si = { 0 };
ASST_AUTO_DEDUCED_ZERO_INIT_END
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = pipe_child_write;
si.hStdError = pipe_child_write;
ASST_AUTO_DEDUCED_ZERO_INIT_START
PROCESS_INFORMATION pi = { nullptr };
ASST_AUTO_DEDUCED_ZERO_INIT_END
BOOL p_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmdline.c_str()), nullptr, nullptr, TRUE,
CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi);
if (p_ret) {
DWORD peek_num = 0;
DWORD read_num = 0;
do {
while (PeekNamedPipe(pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
if (ReadFile(pipe_read, pipe_buffer.get(), peek_num, &read_num, nullptr)) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
}
}
} while (WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT);
DWORD exit_ret = 255;
GetExitCodeProcess(pi.hProcess, &exit_ret);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
CloseHandle(pipe_read);
CloseHandle(pipe_child_write);
#else
static constexpr int PIPE_READ = 0;
static constexpr int PIPE_WRITE = 1;
int pipe_in[2] = { 0 };
int pipe_out[2] = { 0 };
int pipe_in_ret = pipe(pipe_in);
int pipe_out_ret = pipe(pipe_out);
if (pipe_in_ret != 0 || pipe_out_ret != 0) {
return {};
}
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int exit_ret = 0;
int child = fork();
if (child == 0) {
// child process
dup2(pipe_in[PIPE_READ], STDIN_FILENO);
dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
// all these are for use by parent only
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
exit_ret = execlp("sh", "sh", "-c", cmdline.c_str(), nullptr);
exit(exit_ret);
}
else if (child > 0) {
// parent process
// close unused file descriptors, these are for child only
close(pipe_in[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
do {
ssize_t read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
while (read_num > 0) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
};
} while (::waitpid(child, &exit_ret, WNOHANG) == 0);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
}
else {
// failed to create child process
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
}
#endif
return pipe_str;
}
std::string callcmd(const std::string& cmdline);
inline std::string demangle(const char* name_from_typeid)
{

View File

@@ -2,7 +2,8 @@
#include "AsstConf.h"
#ifdef _WIN32
#include <WinUser.h>
#include "AsstPlatformWin32.h"
#include <ws2tcpip.h>
#else
#include <fcntl.h>
#include <sys/wait.h>
@@ -38,27 +39,6 @@ asst::Controller::Controller(AsstCallback callback, void* callback_arg)
LogTraceFunction;
#ifdef _WIN32
// 安全属性描述符
m_pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
m_pipe_sec_attr.lpSecurityDescriptor = nullptr;
m_pipe_sec_attr.bInheritHandle = TRUE;
// 创建管道,本进程读-子进程写
BOOL pipe_read_ret = CreatePipe(&m_pipe_read, &m_pipe_child_write, &m_pipe_sec_attr, PipeBuffSize);
// 创建管道,本进程写-子进程读
BOOL pipe_write_ret = CreatePipe(&m_pipe_write, &m_pipe_child_read, &m_pipe_sec_attr, PipeBuffSize);
if (!pipe_read_ret || !pipe_write_ret) {
throw "controller pipe created failed";
}
m_child_startup_info.cb = sizeof(STARTUPINFO);
m_child_startup_info.dwFlags = STARTF_USESTDHANDLES;
m_child_startup_info.wShowWindow = SW_HIDE;
// 重定向子进程的读写
m_child_startup_info.hStdInput = m_pipe_child_read;
m_child_startup_info.hStdOutput = m_pipe_child_write;
m_child_startup_info.hStdError = m_pipe_child_write;
m_support_socket = false;
do {
@@ -111,13 +91,7 @@ asst::Controller::~Controller()
release();
}
#ifdef _WIN32
CloseHandle(m_pipe_read);
CloseHandle(m_pipe_write);
CloseHandle(m_pipe_child_read);
CloseHandle(m_pipe_child_write);
#else
#ifndef _WIN32
close(m_pipe_in[PIPE_READ]);
close(m_pipe_in[PIPE_WRITE]);
close(m_pipe_out[PIPE_READ]);
@@ -228,69 +202,181 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
using namespace std::chrono;
// LogTraceScope(std::string(__FUNCTION__) + " | `" + cmd + "`");
std::string pipe_data;
std::vector<uchar> pipe_data;
std::vector<uchar> sock_data;
auto start_time = steady_clock::now();
auto check_timeout = [&]() -> bool {
return timeout && timeout < duration_cast<milliseconds>(steady_clock::now() - start_time).count();
};
#ifdef _WIN32
DWORD err;
HANDLE pipe_parent_read, pipe_child_write;
SECURITY_ATTRIBUTES sa_inherit { .nLength = sizeof(SECURITY_ATTRIBUTES), .bInheritHandle = TRUE };
if (!asst::win32::CreateOverlappablePipe(&pipe_parent_read, &pipe_child_write, nullptr, &sa_inherit, PipeBuffSize, true,
false)) {
err = GetLastError();
Log.error("CreateOverlappablePipe failed, err", err);
return std::nullopt;
}
STARTUPINFOW si {};
si.cb = sizeof(STARTUPINFOW);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = pipe_child_write;
si.hStdError = pipe_child_write;
ASST_AUTO_DEDUCED_ZERO_INIT_START
PROCESS_INFORMATION process_info = { nullptr }; // 进程信息结构体
ASST_AUTO_DEDUCED_ZERO_INIT_END
BOOL create_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmd.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW,
nullptr, nullptr, &m_child_startup_info, &process_info);
auto cmdline_osstr = asst::utils::to_osstring(cmd);
BOOL create_ret = CreateProcessW(nullptr, &cmdline_osstr[0], nullptr, nullptr, TRUE, 0, nullptr,
nullptr, &si, &process_info);
if (!create_ret) {
Log.error("Call `", cmd, "` create process failed, ret", create_ret);
return std::nullopt;
}
if (!recv_by_socket) {
DWORD peek_num = 0;
DWORD read_num = 0;
std::unique_lock<std::mutex> pipe_lock(m_pipe_mutex);
do {
// DWORD write_num = 0;
// WriteFile(parent_write, cmd.c_str(), cmd.size(), &write_num, nullptr);
while (PeekNamedPipe(m_pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
if (ReadFile(m_pipe_read, m_pipe_buffer.get(), PipeBuffSize, &read_num, nullptr)) {
pipe_data.insert(pipe_data.end(), m_pipe_buffer.get(), m_pipe_buffer.get() + read_num);
CloseHandle(pipe_child_write);
std::vector<HANDLE> wait_handles;
wait_handles.reserve(3);
bool process_running = true;
bool pipe_eof = false;
bool accept_pending = false;
bool socket_eof = false;
OVERLAPPED pipeov { .hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr) };
(void)ReadFile(pipe_parent_read, m_pipe_buffer.get(), PipeBuffSize, nullptr, &pipeov);
OVERLAPPED sockov {};
SOCKET client_socket = INVALID_SOCKET;
if (recv_by_socket) {
sockov.hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
DWORD dummy;
if (!m_AcceptEx(m_server_sock, client_socket, m_socket_buffer.get(),
SocketBuffSize - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in) + 16,
sizeof(sockaddr_in) + 16, &dummy, &sockov)) {
err = WSAGetLastError();
if (err == ERROR_IO_PENDING) {
accept_pending = true;
}
else {
Log.trace("AcceptEx failed, err:", err);
accept_pending = false;
socket_eof = true;
}
}
}
while (1) {
wait_handles.clear();
if (process_running) wait_handles.push_back(process_info.hProcess);
if (!pipe_eof) wait_handles.push_back(pipeov.hEvent);
if (recv_by_socket && ((accept_pending && process_running) || !socket_eof)) {
wait_handles.push_back(sockov.hEvent);
}
if (wait_handles.empty()) break;
auto elapsed = steady_clock::now() - start_time;
auto wait_time = std::min(timeout - duration_cast<milliseconds>(elapsed).count(), 0xFFFFFFFELL);
if (wait_time < 0) break;
auto wait_result =
WaitForMultipleObjectsEx((DWORD)wait_handles.size(), &wait_handles[0], FALSE, (DWORD)wait_time, TRUE);
HANDLE signaled_object = INVALID_HANDLE_VALUE;
if (wait_result >= WAIT_OBJECT_0 && wait_result < WAIT_OBJECT_0 + wait_handles.size()) {
signaled_object = wait_handles[(size_t)wait_result - WAIT_OBJECT_0];
}
else if (wait_result == WAIT_TIMEOUT) {
continue;
}
else {
// something bad happened
err = GetLastError();
throw std::system_error(std::error_code(err, std::system_category()));
}
if (signaled_object == process_info.hProcess) {
process_running = false;
}
else if (signaled_object == pipeov.hEvent) {
// pipe read
DWORD len = 0;
if (GetOverlappedResult(pipe_parent_read, &pipeov, &len, FALSE)) {
pipe_data.insert(pipe_data.end(), m_pipe_buffer.get(), m_pipe_buffer.get() + len);
(void)ReadFile(pipe_parent_read, m_pipe_buffer.get(), PipeBuffSize, nullptr, &pipeov);
}
else {
err = GetLastError();
if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE) {
pipe_eof = true;
}
}
}
else if (signaled_object == sockov.hEvent) {
if (accept_pending) {
// AcceptEx, client_socker is connected and first chunk of data is received
DWORD len = 0;
if (GetOverlappedResult(reinterpret_cast<HANDLE>(m_server_sock), &sockov, &len, FALSE)) {
accept_pending = false;
if (recv_by_socket)
sock_data.insert(sock_data.end(), m_socket_buffer.get(), m_socket_buffer.get() + len);
if (len == 0) {
socket_eof = true;
closesocket(client_socket);
}
else {
// reset the overlapped since we reuse it for different handle
auto event = sockov.hEvent;
sockov = {};
sockov.hEvent = event;
(void)ReadFile(reinterpret_cast<HANDLE>(client_socket), m_socket_buffer.get(), PipeBuffSize,
nullptr, &sockov);
}
}
}
else {
// ReadFile
DWORD len = 0;
if (GetOverlappedResult(reinterpret_cast<HANDLE>(client_socket), &sockov, &len, FALSE)) {
if (recv_by_socket)
sock_data.insert(sock_data.end(), m_socket_buffer.get(), m_socket_buffer.get() + len);
if (len == 0) {
socket_eof = true;
closesocket(client_socket);
}
else {
(void)ReadFile(reinterpret_cast<HANDLE>(client_socket), m_socket_buffer.get(), PipeBuffSize,
nullptr, &sockov);
}
}
else {
//err = GetLastError();
socket_eof = true;
}
}
} while (WaitForSingleObject(process_info.hProcess, 0) == WAIT_TIMEOUT && !check_timeout());
}
else {
std::unique_lock<std::mutex> pipe_lock(m_pipe_mutex);
fd_set fdset = { 0 };
FD_SET(m_server_sock, &fdset);
constexpr int TimeoutMilliseconds = 5000;
timeval select_timeout = { TimeoutMilliseconds / 1000, (TimeoutMilliseconds % 1000) * 1000 };
select(static_cast<int>(m_server_sock) + 1, &fdset, nullptr, nullptr, &select_timeout);
if (FD_ISSET(m_server_sock, &fdset)) {
SOCKET client_sock = ::accept(m_server_sock, nullptr, nullptr);
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&TimeoutMilliseconds),
sizeof(int));
int recv_size = 0;
do {
recv_size = ::recv(client_sock, (char*)m_socket_buffer.get(), SocketBuffSize, NULL);
if (recv_size < 0) {
Log.error("recv error", recv_size);
break;
}
pipe_data.insert(pipe_data.end(), m_socket_buffer.get(), m_socket_buffer.get() + recv_size);
} while (recv_size > 0 && !check_timeout());
::closesocket(client_sock);
}
WaitForSingleObject(process_info.hProcess, TimeoutMilliseconds);
}
DWORD exit_ret = 0;
GetExitCodeProcess(process_info.hProcess, &exit_ret);
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
CloseHandle(pipe_parent_read);
CloseHandle(pipeov.hEvent);
if (recv_by_socket) {
if (!socket_eof) closesocket(client_socket);
CloseHandle(sockov.hEvent);
}
#else
auto check_timeout = [&]() -> bool {
return timeout && timeout < duration_cast<milliseconds>(steady_clock::now() - start_time).count();
};
int exit_ret = 0;
m_child = fork();
if (m_child == 0) {
@@ -333,11 +419,11 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
Log.trace("Call `", cmd, "` ret", exit_ret, ", output:", pipe_data, ", cost", duration, "ms");
}
else {
Log.trace("Call `", cmd, "` ret", exit_ret, ", output size:", pipe_data.size(), ", cost", duration, "ms");
Log.trace("Call `", cmd, "` ret", exit_ret, ", stdout size:", pipe_data.size(), ", socket size:", sock_data.size(), ", cost", duration, "ms");
}
if (!exit_ret) {
return pipe_data;
return recv_by_socket ? sock_data : pipe_data;
}
else if (m_inited) {
// 这里用 m_inited 限制了仅递归一层,修改需要注意下
@@ -509,8 +595,19 @@ std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::st
if (m_server_sock == INVALID_SOCKET) {
return std::nullopt;
}
DWORD dummy;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
auto err = WSAIoctl(m_server_sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx),
&m_AcceptEx, sizeof(m_AcceptEx), &dummy, NULL, NULL);
if (err == SOCKET_ERROR) {
err = WSAGetLastError();
Log.error("failed to resolve AcceptEx, err:", err);
closesocket(m_server_sock);
return std::nullopt;
}
m_server_addr.sin_family = PF_INET;
m_server_addr.sin_addr.s_addr = inet_addr(local_address.c_str());
inet_pton(AF_INET, local_address.c_str(), &m_server_addr.sin_addr);
#else
// Linux, todo
#endif

View File

@@ -1,5 +1,10 @@
#pragma once
#ifdef _WIN32
#include "SafeWindows.h"
#include <mswsock.h>
#endif
#include "AsstConf.h"
#include <atomic>
@@ -13,10 +18,6 @@
#include <string>
#include <thread>
#ifdef _WIN32
#include <Windows.h>
#endif
#include "NoWarningCVMat.h"
#include "AsstMsg.h"
@@ -109,18 +110,13 @@ namespace asst
std::unique_ptr<char[]> m_socket_buffer = nullptr;
std::mutex m_socket_mutex;
#ifdef _WIN32
HANDLE m_pipe_read = nullptr; // 读管道句柄
HANDLE m_pipe_write = nullptr; // 写管道句柄
HANDLE m_pipe_child_read = nullptr; // 子进程的读管道句柄
HANDLE m_pipe_child_write = nullptr; // 子进程的写管道句柄
ASST_AUTO_DEDUCED_ZERO_INIT_START
SECURITY_ATTRIBUTES m_pipe_sec_attr = { 0 }; // 管道安全描述符
STARTUPINFOA m_child_startup_info = { 0 }; // 子进程启动信息
WSADATA m_wsa_data = { 0 };
WSADATA m_wsa_data {};
SOCKET m_server_sock = 0ULL;
sockaddr_in m_server_addr = { 0 };
sockaddr_in m_server_addr {};
LPFN_ACCEPTEX m_AcceptEx = nullptr;
ASST_AUTO_DEDUCED_ZERO_INIT_END
#else

View File

@@ -102,6 +102,7 @@
<ClInclude Include="RoguelikeTask.h" />
<ClInclude Include="RuntimeStatus.h" />
<ClInclude Include="SingletonHolder.hpp" />
<ClInclude Include="SafeWindows.h" />
<ClInclude Include="StageDropsConfiger.h" />
<ClInclude Include="StageDropsImageAnalyzer.h" />
<ClInclude Include="StageDropsTaskPlugin.h" />

View File

@@ -399,6 +399,9 @@
<ClInclude Include="AsstImageIo.hpp">
<Filter>头文件\Utils</Filter>
</ClInclude>
<ClInclude Include="SafeWindows.h">
<Filter>头文件\Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Controller.cpp">

View File

@@ -9,7 +9,7 @@
#include "Logger.hpp"
#ifdef _WIN32
#include <windows.h>
#include "SafeWindows.h"
#include <format>
static std::filesystem::path prepare_paddle_dir(const std::filesystem::path& dir, bool* is_temp);
#else

View File

@@ -0,0 +1,4 @@
#pragma once
#include <winsock2.h>
#include <windows.h>