微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法作为 c 中的子进程输入到新控制台

如何解决无法作为 c 中的子进程输入到新控制台

我正在使用 Windows 10。

这是我基于此文档的代码

Creating a Child Process with Redirected Input and Output

这里是Parent进程的代码(我只修改CreateChildProcess(),其他都一样):

void CreateChildProcess()
// Create a child process that uses the prevIoUsly created pipes for STDIN and STDOUT.
{
    TCHAR szCmdline[] = TEXT("ChildProcess");
    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;

    Security_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(Security_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create the child process.
    //"C:\\Windows\\System32\\notepad.exe"
    char(*exeName) = "C:\\Users\\kch79\\source\\repos\\MainProcess\\Debug\\ChildProcess.exe";
    bSuccess = CreateProcess(exeName,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 

    //WaitForInputIdle(piProcInfo.hProcess,INFINITE);

     // If an error occurs,exit the application. 
    if (!bSuccess)
        ErrorExit(TEXT("CreateProcess"));
    else
    {
        // Close handles to the child process and its primary thread.
        // Some applications might keep these handles to monitor the status
        // of the child process,for example. 

        WaitForSingleObject(piProcInfo.hProcess,INFINITE);

        CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);

        // Close handles to the stdin and stdout pipes no longer needed by the child process.
        // If they are not explicitly closed,there is no way to recognize that the child process has ended.

        CloseHandle(g_hChildStd_OUT_Wr);
        CloseHandle(g_hChildStd_IN_Rd);
    }
}

这里是子进程的代码(我只添加scanf()):

#include <windows.h>
#include <stdio.h>

#pragma warning(disable:4996)

#define BUFSIZE 4096 

int main(void)
{
    CHAR chBuf[BUFSIZE];
    DWORD dwRead,dwWritten;
    HANDLE hStdin,hStdout;
    BOOL bSuccess;

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    hStdin = GetStdHandle(STD_INPUT_HANDLE);
    if (
        (hStdout == INVALID_HANDLE_VALUE) ||
        (hStdin == INVALID_HANDLE_VALUE)
        )
        ExitProcess(1);

    // Send something to this process's stdout using printf.
    printf("\n ** This is a message from the child process. ** \n");
    int number = 0;
    scanf("%d",&number);
    printf("%d\n",number);
    //SetConsoleMode(hStdin,ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
    //SetConsoleMode(hStdout,ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);

    // This simple algorithm uses the existence of the pipes to control execution.
    // It relies on the pipe buffers to ensure that no data is lost.
    // Larger applications would use more advanced process control.

    for (;;)
    {
        // Read from standard input and stop on error or no data.
        bSuccess = ReadFile(hStdin,chBuf,BUFSIZE,&dwRead,NULL);

        if (!bSuccess || dwRead == 0)
            break;

        // Write to standard output and stop on error.
        bSuccess = WriteFile(hStdout,dwRead,&dwWritten,NULL);

        if (!bSuccess)
            break;
    }
    return 0;
}

这些代码仅适用于 printf(),但不适用于 scanf()

CreateProcess() 创建的新控制台窗口什么也不做。

我想控制控制台,但如何控制?

请告诉我我做错了什么。

解决方法

因为你通过如下代码将子进程的输入句柄重定向到管道:

CreatePipe(&g_hChildStd_IN_Rd,&g_hChildStd_IN_Wr,&saAttr,0)
......
siStartInfo.hStdInput = g_hChildStd_IN_Rd;

所以你的子进程不能在新的控制台输入,而是需要通过父进程的管道输入。当然也可以将子进程的输入句柄设置为NULL

siStartInfo.hStdInput = NULL;

这样可以在子进程中输入,但同时父进程不能向子进程输入消息。

当然建议你把下面的代码放在main函数的最后,这样就可以观察到父进程得到子进程的输入。

WaitForSingleObject(piProcInfo.hProcess,INFINITE);

完整代码:

#include <windows.h> 
#include <tchar.h>
#include <stdio.h> 
#include <strsafe.h>

#define BUFSIZE 4096 

HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;

void CreateChildProcess(void);
void WriteToPipe(void);
void ReadFromPipe(void);
void ErrorExit(PTSTR);
PROCESS_INFORMATION piProcInfo;

int _tmain()
{
    SECURITY_ATTRIBUTES saAttr;

    printf("\n->Start of parent execution.\n");

    // 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,0))
        ErrorExit(TEXT("StdoutRd CreatePipe"));

    // Ensure the read handle to the pipe for STDOUT is not inherited.

    if (!SetHandleInformation(g_hChildStd_OUT_Rd,HANDLE_FLAG_INHERIT,0))
        ErrorExit(TEXT("Stdout SetHandleInformation"));


    if (!SetHandleInformation(g_hChildStd_IN_Wr,0))
        ErrorExit(TEXT("Stdin SetHandleInformation"));

    // Create the child process. 

    CreateChildProcess();

    // Get a handle to an input file for the parent. 
    // This example assumes a plain text file and uses string output to verify data flow. 
    g_hInputFile = CreateFile(
        L"D:\\test\\test.txt",GENERIC_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL);

    if (g_hInputFile == INVALID_HANDLE_VALUE)
        ErrorExit(TEXT("CreateFile"));

    // Write to the pipe that is the standard input for a child process. 
    // Data is written to the pipe's buffers,so it is not necessary to wait
    // until the child process is running before writing data.

    WriteToPipe();
    printf("\n->Contents of %S written to child STDIN pipe.\n",L"D:\\test\\test.txt");

    // Read from pipe that is the standard output for child process. 

    printf("\n->Contents of child process STDOUT:\n\n");
    ReadFromPipe();

    printf("\n->End of parent execution.\n");

    // The remaining open handles are cleaned up when this process terminates. 
    // To avoid resource leaks in a larger application,close handles explicitly. 
    WaitForSingleObject(piProcInfo.hProcess,INFINITE);
    return 0;
}

void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
    TCHAR szCmdline[] = TEXT("ChildProcess");
    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 = NULL;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create the child process. 
    TCHAR exeName[] = L"D:\\VS_test_projects\\Project2\\Debug\\c.exe";
    bSuccess = CreateProcess(exeName,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)
        ErrorExit(TEXT("CreateProcess"));
}

void WriteToPipe(void)

// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data. 
{
    DWORD dwRead,dwWritten;
    CHAR chBuf[BUFSIZE] = "";
    BOOL bSuccess = FALSE;

    for (;;)
    {
        bSuccess = ReadFile(g_hInputFile,chBuf,BUFSIZE,&dwRead,NULL);
        if (!bSuccess || dwRead == 0) break;

        bSuccess = WriteFile(g_hChildStd_IN_Wr,dwRead,&dwWritten,NULL);
        if (!bSuccess) break;
    }

    // Close the pipe handle so the child process stops reading. 

    if (!CloseHandle(g_hChildStd_IN_Wr))
        ErrorExit(TEXT("StdInWr CloseHandle"));
}

void ReadFromPipe(void)

// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT. 
// Stop when there is no more data. 
{
    DWORD dwRead,dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    for (;;)
    {
        bSuccess = ReadFile(g_hChildStd_OUT_Rd,NULL);
        if (!bSuccess || dwRead == 0) break;

        bSuccess = WriteFile(hParentStdOut,NULL);
        if (!bSuccess) break;
    }
}

void ErrorExit(PTSTR lpszFunction)

// Format a readable error message,display a message box,// and exit from the application.
{
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,dw,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,NULL);

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,LocalSize(lpDisplayBuf) / sizeof(TCHAR),TEXT("%s failed with error %d: %s"),lpszFunction,lpMsgBuf);
    MessageBox(NULL,(LPCTSTR)lpDisplayBuf,TEXT("Error"),MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(1);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?