将输入\输出管道从父进程重定向到cmd子进程C / C ++ WinApi

Pch12_

我一直在尝试运行一个类似于cmd输入\输出控制台的父进程。这样做的目的是为了将来使用,但现在我正试图隔离此功能,以使事情变得正确。

我要在这里实现的是用户将其输入到一个简单的cmd子进程的输入,获取输出并继续发送命令,同时保持该进程运行。问题是cmd进程在第一个命令被执行后立即关闭被执行。我粘贴了第一个命令之后发生的结果的输出,一旦我继续尝试并输入更多命令,就会出现一个问题,即句柄无效(因为进程已终止)。

帮助将不胜感激!

主要代码:

#define  _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>
#define bzero(p,size) (void) memset((p), 0 , (size))


// Constant
#define BUFSIZE 4096
// Global variables
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;


// Create a child process that uses the previously created pipes for STDIN and STDOUT.
PROCESS_INFORMATION CreateChildProcess()
{
    // The following should be the child executable, see the next program example
    // Change the path accordingly...
    WCHAR szCmdline[] = L"cmd.exe";
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;
    BOOL bSuccess = FALSE;
    // Set up members of the PROCESS_INFORMATION structure
    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
    // Set up members of the STARTUPINFO structure
    // This structure specifies the STDIN and STDOUT handles for redirection
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.hStdError = g_hChildStd_OUT_Wr;
    siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
    siStartInfo.hStdInput = g_hChildStd_IN_Rd;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
    // Create the child process
    bSuccess = CreateProcess(NULL, // Use szCmdLine
        szCmdline,     // command line
        NULL,          // process security attributes
        NULL,          // primary thread security attributes
        TRUE,          // handles are inherited
        CREATE_NEW_CONSOLE,             // creation flags
        NULL,          // use parent's environment
        NULL,          // use parent's current directory
        &siStartInfo,  // STARTUPINFO pointer
        &piProcInfo);  // receives PROCESS_INFORMATION
     // If an error occurs, exit the application.
    if (!bSuccess)
        printf("Error creating process, %d\n", GetLastError());

    else
    {
        wprintf(L"\nChild process ID is : %u\n", GetCurrentProcessId());
        wprintf(L"Child thread ID is : %u\n", GetCurrentThreadId());
        /*
        if (CloseHandle(piProcInfo.hProcess) != 0)
            wprintf(L"piProcInfo.hProcess handle was closed!\n");
        else
            printf("Error closing process , %d\n", GetLastError());

        if (CloseHandle(piProcInfo.hThread) != 0)
            wprintf(L"piProcInfo.hThread handle was closed!\n");
        else
            printf("Error closing process thread handle, %d\n", GetLastError());
            */
    }
    return piProcInfo;
}

void WriteToPipe(char * command)
{
    DWORD dwWritten;
    DWORD dwRead;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    bSuccess = WriteFile(g_hChildStd_IN_Wr, (LPVOID)command , (DWORD)strlen(command), &dwWritten, NULL);
    printf("Command: %s\n", command);
    if (!bSuccess)
    {
        wprintf(L"\nWriteFile() - Failed to write to pipe for child\'s STDIN! Error %u\n", GetLastError());
        //break;
    }
    else
        wprintf(L"\nWriteFile() - writing to the pipe for the child\'s STDIN...\n");
    // Close the pipe handle so the child process stops reading
    if (!CloseHandle(g_hChildStd_IN_Wr))
        printf("Error closing STDIN handle, %d\n", GetLastError());
    else
        wprintf(L"Closing the pipe handle...\n");

    //Read from pipe
    bSuccess = FALSE;
    bzero(chBuf, sizeof(chBuf));
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (!CloseHandle(g_hChildStd_OUT_Wr))
        printf("Error closing STDOUT handle, %d\n", GetLastError());
    for (;;)
    {
        bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
        if (!bSuccess || dwRead == 0)
        {
            wprintf(L"\nReadFile() from child's standard output failed! Error %u\n", GetLastError());
            break;
        }
        bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
        if (!bSuccess)
        {
            wprintf(L"\nWriteFile() to parent's standard output failed! Error %u\n", GetLastError());
            break;
        }
    }
}

int main()
{
    PROCESS_INFORMATION pi;
    char filename[100];
    ZeroMemory(&filename, sizeof(filename));
    strcpy(filename, "commands.txt");
    SECURITY_ATTRIBUTES saAttr;
    wprintf(L"Parent process ID %u\n", GetCurrentProcessId());
    // Set the bInheritHandle flag so pipe handles are inherited
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
    // Create a pipe for the child process's STDOUT
    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
        printf("Create pipe for STDOUT failed,%d\n", GetLastError());
    else
        wprintf(L"CreatePipe() - pipe for child process\'s STDOUT pipe was created!\n");
    // Ensure the read handle to the pipe for STDOUT is not inherited
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
        printf("Create handle for STDOUT failed,%d\n", GetLastError());
    else
        wprintf(L"SetHandleInformation() - pipe STDOUT read handle is not inherited!\n");
    // Create a pipe for the child process's STDIN
    if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
        printf("Create pipe for STDIN failed,%d\n", GetLastError());
    else
        wprintf(L"CreatePipe() - pipe for child process\'s STDIN was created!\n");
    // Ensure the write handle to the pipe for STDIN is not inherited
    if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
        printf("Error getting handle on STDIN,%d\n", GetLastError());
    else
        wprintf(L"Stdin SetHandleInformation() - pipe STDIN read handle is not inherited!\n");
    // Create the child process
    wprintf(L"Creating the child process...\n");
    pi = CreateChildProcess();
    char chr[1000];
    for (;;)
    {
        bzero(chr, sizeof(chr));
        printf("Enter a character: ");
        scanf("%s", chr);
        strcat(chr, "\n");
        if(strncmp(chr,"exit",4) == 0)
            break;
        WriteToPipe(chr);
    }
    if (CloseHandle(pi.hProcess) != 0)
        wprintf(L"piProcInfo.hProcess handle was closed!\n");
    else
        printf("Error closing process , %d\n", GetLastError());

    if (CloseHandle(pi.hThread) != 0)
        wprintf(L"piProcInfo.hThread handle was closed!\n");
    else
        printf("Error closing process thread handle, %d\n", GetLastError());
    printf("End of parent execution.\n");
    return 0;

}

输出:

Parent process ID 10580
CreatePipe() - pipe for child process's STDOUT pipe was created!
SetHandleInformation() - pipe STDOUT read handle is not inherited!
CreatePipe() - pipe for child process's STDIN was created!
Stdin SetHandleInformation() - pipe STDIN read handle is not inherited!
Creating the child process...

Child process ID is : 10580
Child thread ID is : 1880
Enter a character: whoami
Command: whoami


WriteFile() - writing to the pipe for the child's STDIN...
Closing the pipe handle...
Microsoft Windows [Version 10.0.18363.836]
(c) 2019 Microsoft Corporation. All rights reserved.

C:\Users\Administrator\Desktop>whoami
Administrator

C:\Users\Administrator\Desktop>Clink v0.4.9 [git:2fd2c2] Copyright (c) 2012-2016 Martin Ridgers
http://mridgers.github.io/clink


ReadFile() from child's standard output failed! Error 109
Enter a character:
Rita Han-MSFT

问题是执行第一个命令后,cmd进程立即关闭。

执行此行后,子进程退出:

if (!CloseHandle(g_hChildStd_IN_Wr))

要解决此问题,您可以使用单独的线程。从控制台输入读取命令的一个线程。另一个线程用于读取已执行命令的结果并打印出来。没有关闭g_hChildStd_IN_Wr手柄。

main()方法中:

HANDLE rThread = CreateThread(NULL, 0, ReceiveCommand, NULL, 0, NULL);

HANDLE oThread = CreateThread(NULL, 0, OutputResult, NULL, 0, NULL);

WaitForSingleObject(rThread, INFINITE);

WriteToPipe功能分为两部分:WriteToPipeReadFromPipe

void WriteToPipe(char * command)
{
    DWORD dwWritten;
    BOOL bSuccess = FALSE;
    bSuccess = WriteFile(g_hChildStd_IN_Wr, (LPVOID)command, (DWORD)strlen(command), &dwWritten, NULL);
    printf("Command: %s\n", command);
    if (!bSuccess)
    {
        wprintf(L"\nWriteFile() - Failed to write to pipe for child\'s STDIN! Error %u\n", GetLastError());
        //break;
    }
    else
        wprintf(L"\nWriteFile() - writing to the pipe for the child\'s STDIN...\n");
}

void ReadFromPipe()
{
    DWORD dwWritten;
    DWORD dwRead;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    DWORD availableBytes;
    DWORD bytesToRead;

    //Read from pipe
    bSuccess = FALSE;
    bzero(chBuf, sizeof(chBuf));
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (!CloseHandle(g_hChildStd_OUT_Wr))
        printf("Error closing STDOUT handle, %d\n", GetLastError());
    for (;;)
    {
        PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, NULL, NULL, &availableBytes, NULL);

        while (availableBytes > 0)
        {
            if (availableBytes <= BUFSIZE)
            {
                bytesToRead = availableBytes;
            }
            else
            {
                bytesToRead = BUFSIZE;
            }

            bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, bytesToRead, &dwRead, NULL);
            if (!bSuccess || dwRead == 0)
            {
                wprintf(L"\nReadFile() from child's standard output failed! Error %u\n", GetLastError());
                break;
            }

            availableBytes -= bytesToRead;

            bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
            if (!bSuccess)
            {
                wprintf(L"\nWriteFile() to parent's standard output failed! Error %u\n", GetLastError());
                break;
            }
        }
    }
}

使用GetConsoleScreenBufferInfo到显示器的光标位置等待从完全的子进程打印输出。在此之前,不要开始接收新命令。

DWORD WINAPI ReceiveCommand(LPVOID lpParameter)
{
    char chr[1000];
    CONSOLE_SCREEN_BUFFER_INFO cbsi;
    if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cbsi))
    {
        curPos = cbsi.dwCursorPosition;
    }

    for (;;)
    {
        while (TRUE)
        {
            Sleep(50);
            if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cbsi))
            {
                // printf error message
                return 0;
            }

            if ((curPos.X == cbsi.dwCursorPosition.X) && (curPos.Y == cbsi.dwCursorPosition.Y))
            {
                // All output of the last command executed have been printed completely.
                break;
            }

            curPos = cbsi.dwCursorPosition;
        }

        bzero(chr, sizeof(chr));
        printf("Enter a character: ");
        scanf("%s", chr);
        strcat(chr, "\n");
        if (strncmp(chr, "exit", 4) == 0)
            break;

        WriteToPipe(chr);
    }

    return 0;
}

DWORD WINAPI OutputResult(LPVOID lpParameter)
{
    ReadFromPipe();
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

C ++ WinAPI老式窗口

来自分类Dev

C ++ Winapi waveOutSetVolume()

来自分类Dev

C ++ Winapi提升

来自分类Dev

C++ WinAPI ReadProcessMemory

来自分类Dev

C ++ WinApi CreateProcess无法使用环境块创建子进程

来自分类Dev

C ++ WinApi CreateProcess无法使用环境块创建子进程

来自分类Dev

C ++ Winapi LONG到标准双精度

来自分类Dev

类内部的C ++ Winapi窗口进程不起作用

来自分类Dev

C ++ Winapi-动画背景的MPEG电影

来自分类Dev

确保线程已启动WinAPI C ++

来自分类Dev

C ++ WinAPI TextOut()更新文本

来自分类Dev

GetOpenFileName时出现C ++ WinAPI错误

来自分类Dev

C ++ WINAPI调用通过GetProcAddress导出的函数

来自分类Dev

如何链接包含WinAPI的C代码?

来自分类Dev

WINAPI / C ++:移动无边界窗口

来自分类Dev

C ++ Winapi-动画背景的MPEG电影

来自分类Dev

填充矩形矩形的PictureBox,C ++ WINAPI

来自分类Dev

确保线程已启动WinAPI C ++

来自分类Dev

C ++ Winapi HWND获取WndProc配置

来自分类Dev

C ++ WINAPI调用通过GetProcAddress导出的函数

来自分类Dev

使用Angular登录WinApi C#

来自分类Dev

c++ winapi SendInput意外行为

来自分类Dev

C ++ WinApi将图像.jpg绘制到新窗口?

来自分类Dev

多个进程按 ctrl-c 将其标准输出管道化到单个进程中会杀死外壳

来自分类Dev

如何在Winapi C / C ++中使用系统MUI资源?

来自分类Dev

C++ winApi 无法处理子窗口事件

来自分类Dev

如何将“ this”指针传递给C ++ WinAPI线程?

来自分类Dev

将位图图像加载到WINApi C ++并显示

来自分类Dev

C ++ WinAPI-Windows关闭终止进程之前进行清理?