控制台进程重定向(Win32, C++)

文章描述了一个C++类CConsoleHelper,用于运行Exe程序,支持命令行参数,以及控制输入输出、超时和错误处理。它通过管道机制管理子进程和通信。
摘要由CSDN通过智能技术生成

CConsoleHelper.h

#pragma once

#include <wtypesbase.h>
#include <string>
#include <vector>
#include <locale>
#include <tchar.h>

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

class CConsoleHelper
{
public:
    CConsoleHelper();
    ~CConsoleHelper();

    //
    // @brief: 运行Exe程序
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    // @param: bNeedInput   是否需要输入内容
    // @param: bNeedOutput  是否需要输出内容
    // @ret: bool
    bool RunProcess(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T(""),
        bool bNeedInput = true,
        bool bNeedOutput = true
    );

    //
    // @brief: 运行Exe程序并获取其输出
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    // @param: dwTimeout  超时(毫秒)
    // @ret: _tstring 输出内容
    static _tstring RunProcessGetOutput(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T(""),
        DWORD dwTimeout = INFINITE
    );

    //
    // @brief: 运行Exe程序(可输入输出)
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    bool RunProcessWithInputOutput(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T("")
    );

    //
    // @brief: 运行Exe程序(仅输入)
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    bool RunProcessOnlyInput(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T("")
    );

    //
    // @brief: 运行Exe程序(仅输出)
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    bool RunProcessOnlyOutput(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T("")
    );

    //
    // @brief: 关闭
    // @ret: bool
    bool Close(void);

    //
    // @brief: 读取内容
    // @param: strContent  输出内容
    // @param: dwTimeout  超时(毫秒)
    // @ret: bool
    bool ReadOutput(_tstring& strContent, DWORD dwTimeout = INFINITE);

    //
    // @brief: 写入内容
    // @param: strContent   输入内容
    // @ret: bool
    bool WriteInput(const _tstring& strContent);

    //
    // @brief: 检测是否处于运行状态
    // @ret: bool
    bool IsRunning(void) const;

    //
    // @brief: 获取退出码
    // @ret: DWORD
    DWORD GetExitCode();

    // 
    // @brief: 获取文件所在文件夹
    // @param: strPath     文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 文件夹        如 D:\Software
    _tstring GetFileDir(const _tstring& strPath);

private:

    //
    // @brief: 运行Exe程序
    // @param: strExePath   可执行程序路径
    // @param: strCmd       命令行
    // @param: strCurDir    程序的当前路径
    // @param: bNeedInput   是否需要输入内容
    // @param: bNeedOutput  是否需要输出内容
    // @ret: bool
    bool _RunProcess(
        const _tstring& strExePath = _T(""),
        const _tstring& strCmd = _T(""),
        const _tstring& strCurDir = _T(""),
        bool bNeedInput = true,
        bool bNeedOutput = true
    );

    //宽字符转其他
    static std::string _WStrToOtherStr(UINT CodePage, const std::wstring& str);

    //其他转宽字符
    static std::wstring _OtherStrToWStr(UINT CodePage, const std::string& str);

    static _tstring _AStrToTStr(const std::string& str);
    static std::string _TStrToAStr(const _tstring& str);

private:
    HANDLE m_hPipeInWr;     //子进程输入写管道句柄
    HANDLE m_hPipeInRd;     //子进程输入读管道句柄
    HANDLE m_hPipeOutWr;    //子进程输出写管道句柄
    HANDLE m_hPipeOutRd;    //子进程输出读管道句柄
    PROCESS_INFORMATION m_childPI;  //控制台进程信息
};

CConsoleHelper.cpp

#include <strsafe.h>
#include "CConsoleHelper.h"

#define PIPE_READ_DATA_SIZE         (1024 * 1024)
#define PIPE_READ_TIME_INTERVAL     (50)

std::string CConsoleHelper::_WStrToOtherStr(UINT CodePage, const std::wstring& str)
{
    std::string strResult;
    LPSTR lpMultiByteStr = NULL;

    do
    {
        int nConverted = 0;

        //计算缓冲区所需的字节大小
        nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
        if (0 == nConverted)
        {
            break;
        }

        //分配内存
        lpMultiByteStr = (LPSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nConverted);
        if (NULL == lpMultiByteStr)
        {
            break;
        }

        //转换
        nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, lpMultiByteStr, nConverted, NULL, NULL);
        if (0 == nConverted)
        {
            break;
        }

        strResult = lpMultiByteStr;

    } while (false);

    //释放缓冲
    if (NULL != lpMultiByteStr)
    {
        ::HeapFree(::GetProcessHeap(), 0, lpMultiByteStr);
        lpMultiByteStr = NULL;
    }

    return strResult;
}

std::wstring CConsoleHelper::_OtherStrToWStr(UINT CodePage, const std::string& str)
{
    std::wstring strResult;
    LPWSTR lpWideStr = NULL;

    do
    {
        int nConverted = 0;

        //计算缓冲区所需的字节大小
        nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
        if (0 == nConverted)
        {
            break;
        }

        //分配缓冲内存
        lpWideStr = (LPWSTR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, nConverted * sizeof(WCHAR));
        if (NULL == lpWideStr)
        {
            break;
        }

        //转换字符串
        nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, lpWideStr, nConverted);
        if (0 == nConverted)
        {
            break;
        }

        strResult = lpWideStr;

    } while (false);

    //释放缓冲
    if (NULL != lpWideStr)
    {
        ::HeapFree(::GetProcessHeap(), 0, lpWideStr);
        lpWideStr = NULL;
    }

    return strResult;
}

_tstring CConsoleHelper::_AStrToTStr(const std::string& str)
{
#ifdef _UNICODE
    return _OtherStrToWStr(CP_ACP, str);
#else
    return str;
#endif
}

std::string CConsoleHelper::_TStrToAStr(const _tstring& str)
{
#ifdef _UNICODE
    return _WStrToOtherStr(CP_ACP, str);
#else
    return str;
#endif
}

CConsoleHelper::CConsoleHelper()
    :
    m_hPipeInWr(NULL),
    m_hPipeInRd(NULL),
    m_hPipeOutWr(NULL),
    m_hPipeOutRd(NULL)
{
    ZeroMemory(&m_childPI, sizeof(m_childPI));
}

CConsoleHelper::~CConsoleHelper()
{
    Close();
}

bool CConsoleHelper::RunProcess(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/,
    bool bNeedInput/* = true*/,
    bool bNeedOutput/* = true*/
)
{
    return _RunProcess(strExePath, strCmd, strCurDir, bNeedInput, bNeedOutput);
}

bool CConsoleHelper::RunProcessWithInputOutput(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/
)
{
    return _RunProcess(strExePath, strCmd, strCurDir, true, true);
}

_tstring CConsoleHelper::RunProcessGetOutput(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/,
    DWORD dwTimeout/* = INFINITE*/
)
{
    CConsoleHelper Console;

    _tstring strContent;
    Console._RunProcess(strExePath, strCmd, strCurDir, false, true);
    Console.ReadOutput(strContent, dwTimeout);
    Console.Close();
    return strContent;
}

bool CConsoleHelper::RunProcessOnlyInput(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/
)
{
    return _RunProcess(strExePath, strCmd, strCurDir, true, false);
}

bool CConsoleHelper::RunProcessOnlyOutput(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/
)
{
    return _RunProcess(strExePath, strCmd, strCurDir, false, true);
}

bool CConsoleHelper::Close(void)
{
    ::CloseHandle(m_hPipeInWr);
    ::CloseHandle(m_hPipeInRd);
    ::CloseHandle(m_hPipeOutWr);
    ::CloseHandle(m_hPipeOutRd);
    m_hPipeInWr = NULL;
    m_hPipeInRd = NULL;
    m_hPipeOutWr = NULL;
    m_hPipeOutRd = NULL;

    if (IsRunning())
    {
        ::TerminateProcess(m_childPI.hProcess, (UINT)(-1));
        ::CloseHandle(m_childPI.hProcess);
        m_childPI.hProcess = NULL;
    }

    return true;
}

bool CConsoleHelper::ReadOutput(_tstring& strContent, DWORD dwTimeout/* = INFINITE*/)
{
    LPSTR lpReadBuf = NULL;
    strContent.clear();

    if (NULL == m_hPipeOutRd)
    {
        return false;
    }

    if (nullptr == lpReadBuf)
    {
        lpReadBuf = (char*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_READ_DATA_SIZE);
    }

    if (nullptr == lpReadBuf)
    {
        return false;
    }

    std::string strRead;
    DWORD readBytes = 0;
    ULONGLONG ullBegin = ::GetTickCount64();

    while (::PeekNamedPipe(m_hPipeOutRd, lpReadBuf, PIPE_READ_DATA_SIZE - 1, &readBytes, 0, NULL))
    {
        //未读取到数据则等待
        if (0 == readBytes)
        {
            //超时则退出
            if (INFINITE != dwTimeout && (::GetTickCount64() - ullBegin >= dwTimeout))
            {
                break;
            }

            ::Sleep(PIPE_READ_TIME_INTERVAL);
            continue;
        }

        if (::ReadFile(m_hPipeOutRd, lpReadBuf, PIPE_READ_DATA_SIZE - 1, &readBytes, NULL))
        {
            lpReadBuf[readBytes] = '\0';
            strRead += lpReadBuf;
        }
    }

    if (nullptr != lpReadBuf)
    {
        ::HeapFree(::GetProcessHeap(), 0, lpReadBuf);
        lpReadBuf = nullptr;
    }

    strContent = _AStrToTStr(strRead);

    return false;
}

bool CConsoleHelper::WriteInput(const _tstring& strContent)
{
    if (!IsRunning())
    {
        return false;
    }

    if (NULL == m_hPipeInRd)
    {
        return false;
    }

    std::string strWrite = _TStrToAStr(strContent);
    strWrite += "\r\n";

    DWORD writeBytes = 0;
    if (FALSE == ::WriteFile(m_hPipeInWr, strWrite.c_str(), (DWORD)strWrite.size(), &writeBytes, NULL))
    {
        return false;
    }

    return true;
}

bool CConsoleHelper::IsRunning(void) const
{
    DWORD dwExitCode = 0;

    if ((NULL != m_childPI.hProcess) &&
        (::GetExitCodeProcess(m_childPI.hProcess, &dwExitCode))
        )
    {
        return STILL_ACTIVE == dwExitCode;
    }

    return false;
}

DWORD CConsoleHelper::GetExitCode()
{
    DWORD dwExitCode = 0;

    if ((NULL != m_childPI.hProcess) &&
        (::GetExitCodeProcess(m_childPI.hProcess, &dwExitCode))
        )
    {
        return dwExitCode;
    }

    return (DWORD)-1;
}

_tstring CConsoleHelper::GetFileDir(const _tstring& strPath)
{
    _tstring strResult;
    size_t nIndex = strPath.find_last_of(_T('\\'));
    if (nIndex != _tstring::npos)
    {
        strResult = strPath.substr(0, nIndex);
    }

    return strResult;
}

bool CConsoleHelper::_RunProcess(
    const _tstring& strExePath/* = _T("")*/,
    const _tstring& strCmd/* = _T("")*/,
    const _tstring& strCurDir/* = _T("")*/,
    bool bNeedInput/* = true*/,
    bool bNeedOutput/* = true*/
)
{
    TCHAR szCmdBuf[MAX_PATH] = { 0 };
    SECURITY_ATTRIBUTES   sa = { 0 };
    STARTUPINFO si = { 0 };
    LPCTSTR lpCurrentDir = NULL;
    _tstring strExeCurrentDir = strCurDir;

    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;
    sa.nLength = sizeof(sa);

    //创建子进程的标准输出管道
    if (!::CreatePipe(&m_hPipeOutRd, &m_hPipeOutWr, &sa, 0))
    {
        return false;
    }

    ::SetHandleInformation(m_hPipeOutRd, HANDLE_FLAG_INHERIT, 0);

    //创建子进程的标准输入管道
    if (!::CreatePipe(&m_hPipeInRd, &m_hPipeInWr, &sa, 0))
    {
        ::CloseHandle(m_hPipeInWr);
        ::CloseHandle(m_hPipeInRd);
        ::CloseHandle(m_hPipeOutWr);
        ::CloseHandle(m_hPipeOutRd);
        return false;
    }

    ::SetHandleInformation(m_hPipeInWr, HANDLE_FLAG_INHERIT, 0);

    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    si.hStdOutput = GetStdHandle(STD_ERROR_HANDLE);

    if (bNeedInput)
    {
        si.hStdInput = m_hPipeInRd;
    }

    if (bNeedOutput)
    {
        si.hStdOutput = m_hPipeOutWr;
        si.hStdError = m_hPipeOutWr;
    }

    //exe路径不为空
    if (!strExePath.empty())
    {
        if (!strCmd.empty())
        {
            ::StringCchPrintf(szCmdBuf, _countof(szCmdBuf), _T("\"%s\" %s"), strExePath.c_str(), strCmd.c_str());
        }
        else
        {
            ::StringCchPrintf(szCmdBuf, _countof(szCmdBuf), _T("\"%s\""), strExePath.c_str());
        }
    }
    //exe路径为空
    else
    {
        ::StringCchPrintf(szCmdBuf, _countof(szCmdBuf), _T("%s"), strCmd.c_str());
    }

    //如果未指定进程当前目录, 则使用进程所在目录
    if (strExeCurrentDir.empty())
    {
        strExeCurrentDir = GetFileDir(strExePath);
    }

    if (!strExeCurrentDir.empty())
    {
        lpCurrentDir = strExeCurrentDir.c_str();
    }

    if (!::CreateProcess(NULL, szCmdBuf, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, lpCurrentDir, &si, &m_childPI))
    {
        ::CloseHandle(m_hPipeInWr);
        ::CloseHandle(m_hPipeInRd);
        ::CloseHandle(m_hPipeOutWr);
        ::CloseHandle(m_hPipeOutRd);
        m_hPipeInWr = NULL;
        m_hPipeInRd = NULL;
        m_hPipeOutWr = NULL;
        m_hPipeOutRd = NULL;
        ZeroMemory(&m_childPI, sizeof(m_childPI));
        return false;
    }

    ::CloseHandle(m_childPI.hThread);
    m_childPI.hThread = NULL;

    return true;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Win32控制台托盘是一种用于在Windows操作系统中的控制台应用程序中添加托盘图标的技术。 Win32是一种面向Windows平台的编程技术。它提供了一套应用程序编程接口(API),开发人员可以使用这些接口来创建和管理Windows应用程序。使用Win32编程技术,开发人员可以通过编写C语言或C++代码来实现控制台应用程序。 控制台应用程序是一种以命令行界面为基础的应用程序,通常通过命令行窗口来操作和显示结果。然而,控制台应用程序通常不支持图形用户界面(GUI)的特性,例如窗口和图标。 然而,通过使用Win32控制台托盘技术,开发人员可以在控制台应用程序中添加托盘图标。托盘图标通常显示在任务栏的系统托盘区域,提供快速访问应用程序的功能。 要实现Win32控制台托盘,开发人员需要使用Win32 API中的相关函数和消息。例如,可以使用Shell_NotifyIcon函数来添加、修改或删除托盘图标,使用Shell_NotifyIcon消息来处理托盘图标的操作和事件。 使用Win32控制台托盘技术,开发人员可以为控制台应用程序添加更多的交互性和易用性。用户可以通过右击托盘图标来打开菜单,执行一些预定义的操作,例如显示控制台窗口、关闭应用程序等。 总而言之,Win32控制台托盘是一种在控制台应用程序中实现托盘图标的技术。通过使用相关的Win32 API函数和消息,开发人员可以为控制台应用程序添加更多的用户交互性和易用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值