C# C++写代码 运行test.bat脚本,获取退出值和脚本运行的输出 控制台要实时输出内容 运行RunBatchFile(“test.bat“);后 要有返回值 显示返回值,最后要暂停

在这里插入图片描述

下面代码使用了异步读取(通过事件)来实时显示脚本输出,并在执行完毕后返回退出值,最后等待用户按键暂停控制台窗口:

using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        int exitCode = RunBatchFile("test.bat");
        Console.WriteLine($"Exit Code: {exitCode}");
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

    static int RunBatchFile(string filePath)
    {
        try
        {
            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = filePath,
                UseShellExecute = false,       // 必须为false以支持重定向
                RedirectStandardOutput = true, // 重定向标准输出
                RedirectStandardError = true,  // 重定向错误输出
                CreateNoWindow = true          // 不显示窗口
            };

            using (Process process = new Process { StartInfo = psi, EnableRaisingEvents = true })
            {
                // 异步处理标准输出
                process.OutputDataReceived += (sender, args) =>
                {
                    if (!string.IsNullOrEmpty(args.Data))
                    {
                        Console.WriteLine(args.Data);
                    }
                };

                // 异步处理错误输出
                process.ErrorDataReceived += (sender, args) =>
                {
                    if (!string.IsNullOrEmpty(args.Data))
                    {
                        Console.Error.WriteLine(args.Data);
                    }
                };

                process.Start();

                // 开始异步读取输出
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit(); // 等待脚本执行结束

                return process.ExitCode; // 返回退出码
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error running batch file: {ex.Message}");
            return -1;
        }
    }
}

代码说明

  1. 异步读取输出
    通过 OutputDataReceivedErrorDataReceived 事件,在脚本执行过程中实时将输出打印到控制台。

  2. 重定向与不显示窗口
    设置 UseShellExecute = falseRedirectStandardOutput = trueRedirectStandardError = trueCreateNoWindow = true,确保可以重定向输出且不弹出额外窗口。

  3. 获取退出码并暂停
    脚本执行完毕后返回退出码,并在控制台中显示,最后调用 Console.ReadKey() 暂停程序,等待用户按键后退出。

这样运行 RunBatchFile("test.bat") 后,控制台会实时显示脚本输出,最后显示退出值并等待用户按键。

用c++也写一个同样的

下面示例代码利用 Windows API(CreateProcess 和管道)实现运行批处理文件、实时输出内容、获取退出码,并在结束后暂停控制台窗口。该代码将标准输出和错误合并到同一个管道中,实时读取并输出到控制台。

#include <windows.h>
#include <iostream>
#include <string>

int RunBatchFile(const std::string& batchFile)
{
    // 设置安全属性,允许管道句柄被子进程继承
    SECURITY_ATTRIBUTES saAttr; 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    // 创建管道,用于重定向子进程的标准输出和错误(合并)
    HANDLE hChildStd_Rd = NULL;
    HANDLE hChildStd_Wr = NULL;
    if (!CreatePipe(&hChildStd_Rd, &hChildStd_Wr, &saAttr, 0))
    {
        std::cerr << "创建管道失败" << std::endl;
        return -1;
    }
    // 确保读句柄不被继承
    if (!SetHandleInformation(hChildStd_Rd, HANDLE_FLAG_INHERIT, 0))
    {
        std::cerr << "设置句柄属性失败" << std::endl;
        return -1;
    }

    // 设置启动信息,指定子进程的标准输出和错误句柄
    PROCESS_INFORMATION piProcInfo;
    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

    STARTUPINFOA siStartInfo;
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA));
    siStartInfo.cb = sizeof(STARTUPINFOA);
    siStartInfo.hStdOutput = hChildStd_Wr;
    siStartInfo.hStdError  = hChildStd_Wr;  // 合并错误输出
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    // 构造命令行:使用 cmd.exe /c 执行批处理文件
    std::string cmdLine = "cmd.exe /c " + batchFile;
    // CreateProcess 要求可写的字符串缓冲区
    char* cmd = new char[cmdLine.size() + 1];
    strcpy_s(cmd, cmdLine.size() + 1, cmdLine.c_str());

    // 创建子进程
    BOOL bSuccess = CreateProcessA(
        NULL,            // 应用程序名称
        cmd,             // 命令行
        NULL,            // 进程安全属性
        NULL,            // 线程安全属性
        TRUE,            // 句柄继承
        0,               // 创建标志
        NULL,            // 使用父进程的环境变量
        NULL,            // 使用父进程的当前目录
        &siStartInfo,    // STARTUPINFO 指针
        &piProcInfo);    // PROCESS_INFORMATION 指针

    delete[] cmd; // 释放申请的内存

    if (!bSuccess)
    {
        std::cerr << "CreateProcess 失败,错误码:" << GetLastError() << std::endl;
        CloseHandle(hChildStd_Rd);
        CloseHandle(hChildStd_Wr);
        return -1;
    }
    else
    {
        // 子进程已经继承写句柄,父进程可以关闭写句柄
        CloseHandle(hChildStd_Wr);

        // 实时读取子进程输出
        const DWORD BUFSIZE = 4096;
        char buffer[BUFSIZE];
        DWORD dwRead;
        BOOL bReadSuccess = FALSE;
        while (true)
        {
            bReadSuccess = ReadFile(hChildStd_Rd, buffer, BUFSIZE - 1, &dwRead, NULL);
            if (!bReadSuccess || dwRead == 0)
                break;
            buffer[dwRead] = '\0';  // 添加字符串结束符
            std::cout << buffer;
        }

        // 等待子进程结束
        WaitForSingleObject(piProcInfo.hProcess, INFINITE);

        // 获取退出码
        DWORD exitCode;
        if (!GetExitCodeProcess(piProcInfo.hProcess, &exitCode))
        {
            exitCode = -1;
        }

        // 关闭句柄
        CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);
        CloseHandle(hChildStd_Rd);

        return static_cast<int>(exitCode);
    }
}

int main()
{
    int exitCode = RunBatchFile("test.bat");
    std::cout << "\n退出码: " << exitCode << std::endl;
    std::cout << "按任意键继续..." << std::endl;
    system("pause");
    return 0;
}

代码说明

  1. 管道设置
    使用 CreatePipe 创建一个管道,并通过 SetHandleInformation 确保读取句柄不被子进程继承。

  2. 启动信息设置
    STARTUPINFOA 中指定了 hStdOutputhStdError 为管道写入端,使用 cmd.exe /c 形式执行批处理文件。

  3. 实时读取输出
    通过 ReadFile 循环读取管道中的数据,将子进程输出实时显示到控制台。

  4. 获取退出码
    使用 WaitForSingleObject 等待子进程结束,然后调用 GetExitCodeProcess 获取批处理文件的退出码。

  5. 暂停控制台
    main 函数中调用 system("pause") 等待用户按键后退出。

这样运行后,控制台会实时显示 test.bat 的输出,结束后显示退出码,并等待用户按键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄人软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值