关于windows下进程重定向输入输出问题
  • 板块灌水区
  • 楼主mc_sunduoai
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/12/23 08:05
  • 上次更新2023/12/23 10:59:16
查看原帖
关于windows下进程重定向输入输出问题
732108
mc_sunduoai楼主2023/12/23 08:05

RT,先放代码

#include <windows.h>
#include <iostream>
bool writeToPipe(HANDLE hPipe, const std::string& input) {
    DWORD bytesWritten = 0;
    if (!WriteFile(hPipe, input.c_str(), static_cast<DWORD>(input.length()), &bytesWritten, NULL)) {
        std::cerr << "写入管道失败" << std::endl;
        return false;
    }
    
    // 发送回车
    const char* newline = "\r\n";
    if (!WriteFile(hPipe, newline, 2, &bytesWritten, NULL)) {
        std::cerr << "写入管道失败" << std::endl;
        return false;
    }
    return true;
}
int main() {
    HANDLE hOutputPipe, hInputPipe;
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;

    // 定义一个安全属性结构
    SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
    saAttr.bInheritHandle = TRUE; // 允许子进程继承句柄

    // 创建输出命名管道
    hOutputPipe = CreateNamedPipe(
        "\\\\.\\pipe\\output_pipe",
        PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        10,
        1024,
        1024,
        NMPWAIT_USE_DEFAULT_WAIT,
        &saAttr  // 将安全属性结构传递给CreateNamedPipe函数
    );

    if (hOutputPipe == INVALID_HANDLE_VALUE) {
        std::cerr << "无法创建输出命名管道" << std::endl;
        return 1;
    }

    // 创建输入命名管道
    hInputPipe = CreateNamedPipe(
        "\\\\.\\pipe\\input_pipe",
        PIPE_ACCESS_INBOUND,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        10,
        1024,
        1024,
        NMPWAIT_USE_DEFAULT_WAIT,
        &saAttr  // 将安全属性结构传递给CreateNamedPipe函数
    );

    if (hInputPipe == INVALID_HANDLE_VALUE) {
        std::cerr << "无法创建输入命名管道" << std::endl;
        CloseHandle(hOutputPipe);
        return 1;
    }

   // 设置启动信息
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.dwFlags = STARTF_USESTDHANDLES;
    siStartInfo.hStdError = hOutputPipe;
    siStartInfo.hStdOutput = hOutputPipe;
    siStartInfo.hStdInput = hInputPipe;

    // 启动Java进程
    if (!CreateProcess(
            NULL,
            "java -jar spigot-1.20.4.jar -nogui",
            NULL,
            NULL,
            TRUE,
            0,
            NULL,
            NULL,
            &siStartInfo,
            &piProcInfo)) {
        std::cerr << "无法启动Java进程" << std::endl;
        CloseHandle(hOutputPipe);
        CloseHandle(hInputPipe);
        return 1;
    }
    std::string input;
	while(1)
	{
		std::cin>>input;
		writeToPipe(hInputPipe, input);
	}
    
    // 等待子进程结束
    WaitForSingleObject(pi.hProcess, INFINITE);

    // 关闭进程和线程的句柄
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

在这段代码中,我首先定义了安全属性结构saAttr,确保所有程序可以连接至管道(昨天在这里被卡了一个小时),然后创建了名为output_pipe和input_pipe的命名管道,其中output_pipe只允许服务端写入,客户端读取,input_pipe只允许客户端写入,服务端读取。然后修改siStartInfo中的启动信息,将hStdOutput绑定在管道output_pipe上,hStdInput绑定在管道input_pipe上,如下

// 设置启动信息
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.dwFlags = STARTF_USESTDHANDLES;
    siStartInfo.hStdError = hOutputPipe;
    siStartInfo.hStdOutput = hOutputPipe;
    siStartInfo.hStdInput = hInputPipe;

然后使用CreateProcess创建新进程执行命令“java -jar spigot-1.20.4.jar -nogui”其中使用siStartInfo作为启动信息。

确保启动后,我循环从屏幕读取内容,并尝试使用writeToPipe函数将信息发送至input_pipe管道,下面是writeToPipe函数的定义

bool writeToPipe(HANDLE hPipe, const std::string& input) {
    DWORD bytesWritten = 0;
    if (!WriteFile(hPipe, input.c_str(), static_cast<DWORD>(input.length()), &bytesWritten, NULL)) {
        std::cerr << "写入管道失败" << std::endl;
        return false;
    }
    
    // 发送回车
    const char* newline = "\r\n";
    if (!WriteFile(hPipe, newline, 2, &bytesWritten, NULL)) {
        std::cerr << "写入管道失败" << std::endl;
        return false;
    }
    return true;
}

在尝试执行发送命令后,WriteFile函数返回错误。通过GetLastError()函数获取到了错误代码5。在微软的官方说明文档中5表示Access is denied.(拒绝访问)。意味着我无法向input_pipe写入内容。随后其编写了另一个程序判断output_pipe是否可用

#include <windows.h>
#include <bits/stdc++.h>

int main() {
    HANDLE hPipe;
    char buffer[1024];
    DWORD bytesRead;

    // 打开管道
    hPipe = CreateFile(
        "\\\\.\\pipe\\output_pipe",  // 管道名称
        GENERIC_READ,                // 只读访问
        0,                           // 不共享
        NULL,                        // 默认安全属性
        OPEN_EXISTING,               // 已存在的管道
        0,                           // 默认标志
        NULL                         // 无模板文件
    );

    if (hPipe != INVALID_HANDLE_VALUE) {
        while(1)
        {
        	ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
        	std::cout <<  buffer;
        	std::memset(buffer,NULL,sizeof(buffer));
		}
        

        // 关闭管道
        CloseHandle(hPipe);
    } else {
        std::cerr << "无法打开管道" << std::endl;
    }

    return 0;
}

程序成功接收到了output_pipe管道输出的内容,意味着管道的定义没有问题。麻烦各位帮我检查一下程序的输如有没有成功重定向到input_pipe上?如果没有,我该怎么做?

2023/12/23 08:05
加载中...