C++执行指令,接收数据

#include <iostream>
#include <windows.h>
#include <string>
#include <thread>
#include <locale>
#include <codecvt>
using namespace std;

// 辅助函数:宽字符转字符串(用于打印/调试)
string WstringToString(const wstring& wstr) {
    wstring_convert<codecvt_utf8<wchar_t>> conv;
    return conv.to_bytes(wstr);
}

// 读取管道内容的辅助函数(增加错误处理)
void ReadPipe(HANDLE hPipe, string& output) {
    char buffer[4096];
    DWORD bytesRead = 0;
    DWORD errCode = 0;

    // 设置管道非阻塞读取(避免无输出时一直阻塞)
    DWORD mode = PIPE_NOWAIT;
    SetNamedPipeHandleState(hPipe, &mode, NULL, NULL);

    while (true) {
        BOOL ret = ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
        errCode = GetLastError();

        // 无数据可读且管道未关闭:短暂休眠后重试
        if (!ret && errCode == ERROR_NO_DATA) {
            Sleep(100);
            continue;
        }

        // 读取成功且有数据:追加到输出
        if (ret && bytesRead > 0) {
            buffer[bytesRead] = '\0';
            output += buffer;
            cout << "[外部程序输出] " << buffer << flush; // flush确保实时输出
        }

        // 读取完成(管道关闭/无更多数据)
        if ((!ret && errCode == ERROR_BROKEN_PIPE) || (ret && bytesRead == 0)) {
            break;
        }
    }
}

int main() 
{
    // 1. 定义命令行(正确的宽字符格式,避免强制转换)
    wstring cmdWstr = L"\"C:\\Users\\demo.exe\" \"C:\\999-07-25-09-"";
    LPWSTR cmdLine = const_cast<LPWSTR>(cmdWstr.c_str()); // 转为可写宽字符指针

    // 打印命令行(调试用,确认路径无错)
    cout << "开始执行指令:" << WstringToString(cmdWstr) << endl;

    // 2. 创建匿名管道
    HANDLE hReadPipe, hWritePipe;
    SECURITY_ATTRIBUTES sa = { 0 };
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) {
        cout << "创建管道失败,错误码:" << GetLastError() << endl;
        return 1;
    }

    // 3. 设置启动信息
    STARTUPINFOW si = { 0 };
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE; // 隐藏窗口(替代CREATE_NO_WINDOW)
    si.hStdOutput = hWritePipe;
    si.hStdError = hWritePipe;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);

    // 4. 启动外部进程
    PROCESS_INFORMATION pi = { 0 };
    BOOL success = CreateProcessW(
        NULL,           // 程序名(从cmdLine中解析)
        cmdLine,        // 完整命令行(宽字符,无强制转换)
        NULL, NULL,
        TRUE,           // 允许继承句柄(关键!)
        0,              // 取消CREATE_NO_WINDOW,改用si.wShowWindow
        NULL, NULL,
        &si, &pi
    );

    if (!success) {
        cout << "启动外部程序失败,错误码:" << GetLastError() << endl;
        CloseHandle(hReadPipe);
        CloseHandle(hWritePipe);
        // 错误码对照:2=文件不存在,5=权限不足,123=路径/参数格式错
        return 1;
    }

    // 5. 关闭管道写端(子进程已继承,当前进程无需保留)
    CloseHandle(hWritePipe);

    // 6. 读取管道内容
    string outputContent;
    thread readThread(ReadPipe, hReadPipe, ref(outputContent));

    // 7. 等待外部程序执行完毕(超时保护:30秒)
    DWORD waitRet = WaitForSingleObject(pi.hProcess, 30000); // 30秒超时
    if (waitRet == WAIT_TIMEOUT) {
        cout << "\n警告:外部程序执行超时(30秒),强制结束进程!" << endl;
        TerminateProcess(pi.hProcess, 1);
    }

    // 8. 等待读取线程结束,清理资源
    readThread.join();
    CloseHandle(hReadPipe);

    // 9. 获取退出码并释放句柄
    DWORD exitCode;
    GetExitCodeProcess(pi.hProcess, &exitCode);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    // 10. 输出结果
    cout << "\n===== 外部程序执行完成 =====" << endl;
    cout << "退出码:" << exitCode << endl;
    if (outputContent.empty()) {
        cout << "捕获的输出内容:无(外部程序未输出任何内容,或启动失败)" << endl;
    }
    else {
        cout << "捕获的输出内容:\n" << outputContent << endl;
    }
    FILE* fp = fopen("D:\\2222.txt", "w");
    fwrite(outputContent.c_str(), 1, outputContent.size(), fp);
    int ret = fclose(fp);
    ret = 100;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值