• 获取CMD执行结果——匿名管道


    实现原理:

      管道是一种在进程间共享数据的机制,其实质是一段共享内存。Windows系统为这段共享的内存设计使用数据流I/O的方式来访问。一个进程读,另一个进程写,这类似于一个管道的两端,因此这种进程间的通信方式称为“管道”。管道分为匿名管道和命名管道。匿名管道只能在父子进程间进行通信,不能在网络间通信,而且数据传输是单向的,只能一端写,另一端读。命名管道可以在任意进程间通信,通信是双向的,任意一端都可读可写,但是在同一时间只能有一端读、一端写。创建命名管道的方式可以获取CMD执行结果的输出内容

    实现过程:

      (1).调用函数CreatePipe创建匿名管道,获取管道数据读取句柄和管道数据写入句柄。

      (2).创建新进程(进程属性为窗口隐藏、窗口的缓存句柄设置为上面得到的管道数据写入句柄)

      (3).调用函数WaitForSingleObject等待命令执行完毕

      (4).调用ReadFile函数根据匿名管道的数据读取句柄从匿名管道的缓冲区中读取数据

      (5).关闭句柄,释放资源

    实现代码:

        //************************************
        // 函数名:CCmdDlg::PipeCmd
        // 返回类型:BOOL
        // 功能:    执行CMD命令, 并获取执行结果数据
        // 参数1:char *pszCmd    cmd命令
        // 参数2:char *pszResultBuffer    接收CMD结果的缓冲区
        // 参数3:DWORD dwResultBufferSize    缓冲区大小(缓冲区要大点,不然接收到的结果不全)
        //************************************
    BOOL CCmdDlg::PipeCmd(char *pszCmd, char *pszResultBuffer, DWORD dwResultBufferSize)
    {
        SECURITY_ATTRIBUTES securityAttributes = { 0 };
        // 设定管道的安全属性
        securityAttributes.bInheritHandle = TRUE;
        securityAttributes.nLength = sizeof(securityAttributes);
        securityAttributes.lpSecurityDescriptor = NULL;
    
        // 创建匿名管道
        HANDLE hReadPipe = NULL;
        HANDLE hWritePipe = NULL;
        BOOL bRet = ::CreatePipe(&hReadPipe, &hWritePipe, &securityAttributes, 0);
        if (FALSE == bRet)
        {
            MessageBox(_T("CreatePipe Error"));
            return FALSE;
        }
    
        STARTUPINFO si = { 0 };
        // 设置新进程参数
        si.cb = sizeof(si);
        si.hStdError = hWritePipe;
        si.hStdOutput = hWritePipe;
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        // 创建新进程执行命令, 将执行结果写入匿名管道中
        PROCESS_INFORMATION pi = { 0 };
        USES_CONVERSION;
        bRet = ::CreateProcess(NULL, A2W(pszCmd), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
        if (FALSE == bRet)
        {
            MessageBox(_T("CreateProcess Error"));
        }
    
        // 等待命令执行结束
        ::WaitForSingleObject(pi.hThread, INFINITE);
        ::WaitForSingleObject(pi.hProcess, INFINITE);
    
        // 从匿名管道中读取结果到输出缓冲区
        ::RtlZeroMemory(pszResultBuffer, dwResultBufferSize);
        ::ReadFile(hReadPipe, pszResultBuffer, dwResultBufferSize, NULL, NULL);
    
        // 关闭句柄, 释放内存
        ::CloseHandle(pi.hThread);
        ::CloseHandle(pi.hProcess);
        ::CloseHandle(hWritePipe);
        ::CloseHandle(hReadPipe);
    
        return TRUE;
    }
  • 相关阅读:
    Extjs Ext.ux.IFrame的用法 以及父子窗口间函数相互调用
    Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
    Java sun.misc.Unsafe类的学习笔记
    Java 并发编程学习笔记 理解CLH队列锁算法
    深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
    Java并发编程学习笔记 深入理解volatile关键字的作用
    JVM Client Server启动设置
    双重检查锁定与延迟初始化
    Tomcat 添加为系统服务 开机自动启动
    配置TOMCAT 修改默认ROOT路径
  • 原文地址:https://www.cnblogs.com/ndyxb/p/12913476.html
Copyright © 2020-2023  润新知