【问题标题】:How can i make createprocess reindirect input success, I have successully get the reindirect out put result我怎样才能使createprocess重定向输入成功,我已经成功地得到了重定向输出结果
【发布时间】:2017-04-17 10:11:51
【问题描述】:

我在互联网上搜索了很多,但大多数都在谈论重定向输出。没有人给出任何成功的重定向输入示例。对于下面的代码,当我运行命令“ipconfig”或“192.168.0.10”时它给出了正确的输出,因为子进程在运行这些命令后结束,不需要输入。但是当我运行命令“ftp”而不是“ipconfig”时,控制台的子进程正在等待下一个输入命令。如您所见,在这种情况下,我尝试将 11111 作为控制台的输入。但是控制台没有收到我的输入命令并永远等待输入命令。如何在此程序中成功响应“ftp”命令并保持控制台运行

#include <windows.h>
#include <fstream>
using namespace std;

int WINAPI WinMain(
                   HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpComLine,
                   int nCmdShow)
{
    SECURITY_ATTRIBUTES secAttr; 
    HANDLE hRead,hWrite;

char command[256];
char testBuf[256] = {0};
    strcpy(command, "ipconfig");
//  strcpy(command, "ping 192.168.0.10")    
//  strcpy(command, "ftp");

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

HANDLE hTxtFile = CreateFile("tmp.txt", GENERIC_ALL, 0, &secAttr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hTxtFile == INVALID_HANDLE_VALUE)
{
    MessageBox(NULL, "Error createfile", NULL, MB_OK);
    return 0;
}
HANDLE hWriteFile = CreateFile("Write.txt", GENERIC_WRITE, 0, &secAttr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hWriteFile == INVALID_HANDLE_VALUE)
{
    MessageBox(NULL, "Error createWritefile", NULL, MB_OK);
    return 0;
}

STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo; 
startupInfo.cb = sizeof(STARTUPINFO); 
GetStartupInfo(&startupInfo); 
startupInfo.hStdError = hTxtFile;    
startupInfo.hStdOutput = hTxtFile;
startupInfo.hStdInput = hWriteFile;
startupInfo.wShowWindow = SW_SHOW; 
startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

char output[10240] = {0};
DWORD bytesRead;

if (!CreateProcess(NULL, command,NULL,NULL,TRUE,NULL,NULL,NULL,&startupInfo,&processInfo)) 
{ 
    MessageBox(NULL, "Error createprocess", NULL, MB_OK);
    CloseHandle(hWrite); 
    CloseHandle(hRead); 
    return FALSE; 
} 

DWORD processExitCode = 0;
strcpy(testBuf, "11111\r\n");
while (GetExitCodeProcess(processInfo.hProcess, &processExitCode))
{
    WriteFile(hWriteFile, testBuf, 7, &bytesRead, NULL);
    if (processExitCode != STILL_ACTIVE) 
    {
        //  MessageBox(NULL, "End process", NULL, MB_OK);
        break;
    }
    Sleep(1000);
}

SetFilePointer(hTxtFile, NULL, NULL, FILE_BEGIN);
ReadFile(hTxtFile, output, 10240, &bytesRead, NULL);
CloseHandle(hTxtFile);

MessageBox(NULL, output, NULL, MB_OK);

return 0;
}

【问题讨论】:

  • 1) 需要关闭句柄,但您不这样做 2) hStdInput 必须有 FILE_GENERIC_READ 访问权限 3) 大多数程序在查看空输入时(NumberOfBytesRead == 0ZwReadFile return STATUS_END_OF_FILE )简单地退出 - 因此您的代码将无法与文件系统文件一起使用。或者您需要在创建进程之前将数据写入hStdInput
  • 4) 一般说明 - 在使用时使用同步共享文件 - 不正确 - 文件共享 CurrentByteOffset。当您调用 WriteFile 时,您不能从您认为的位置写入,因为子进程可以更改位置(这可以通过在 OVERLAPPED 中使用直接偏移来避免)。您在共享文件对象中的写入更改 CurrentByteOffset 并影响子进程 5)使用 processExitCode != STILL_ACTIVE 不是 100% 可靠的方式 - 如果子调用 ExitProcess(STILL_ACTIVE) 怎么办?
  • 我已经在我的项目中发现了问题,所以基本上当我们使用 STARTF_USESTDHANDLES 属性时。 createprocess 将创建非交互式控制台,这意味着它只能在 createprocess 调用中运行一个命令行。知道我可以使用 createprocess 创建一个交互式重定向控制台,该控制台根据最后一个控制台输出获取用户输入吗?非常感谢
  • 没有“非交互式控制台”之类的东西,由于您正在重定向输入,因此无论如何都不涉及控制台。问题是您试图像使用管道一样使用文件,这是行不通的。
  • stackoverflow.com/questions/26398214/redirect-ftp-pipe-in-c 在这里,我更改了我的代码,它现在可以正常工作,但我遇到了与这个 OP 相同的问题。当我们在真实控制台中输入“ftp”或“wmic”时,我们会收到“ftp>”,而当我们输入像“123”这样的无效命令时,我们会收到“无效命令”。但是这种父进程和子控制台进程之间的交互操作并没有发生在我的代码或我在互联网上找到的所有重定向程序中。所以还没有真正看到一个 VC 控制台像真正的 cmd.exe 控制台一样工作

标签: c++ winapi createprocess


【解决方案1】:

重定向(不是“重定向”)输入的工作方式与重定向输出相同。当然,数据的流动方向是相反的。这意味着进程从文件中读取。这反过来意味着当您打开一个句柄进行写入时,就像您在示例代码中所做的那样:

HANDLE hWriteFile = CreateFile("Write.txt", GENERIC_WRITE, ...);

进程将无法从中读取。您必须打开文件才能阅读:

HANDLE hWriteFile = CreateFile("Write.txt", GENERIC_READ, ...);

但是,这也意味着您必须提前准备好要发送到流程的输入。 在创建进程之后写入文件没有帮助。

如果您事先不知道必须发送到进程的数据,则不能将文件用于标准输入,但必须使用其他东西,例如(命名或匿名)管道。

【讨论】:

    【解决方案2】:

    您必须重定向控制台输出,然后将缓冲区写入文件

    1)

        /* Create a pipe for the child process's STDOUT */
        if(!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
            BAIL_OUT(-1);
    

    2)

        /* Duplicate the pipe HANDLE */
        if (!DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
            BAIL_OUT(-1);
    

    3)

    CHAR chBuf[BUFSIZE];
        DWORD dwRead;
        DWORD dwAvail = 0;
        if (!PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &dwAvail, NULL) || !dwAvail)
            return;
        if (!ReadFile(hChildStdoutRdDup, chBuf, min(BUFSIZE - 1, dwAvail), &dwRead, NULL) || !dwRead)
            return;
        chBuf[dwRead] = 0;
    

    请在此处找到更多详细信息: https://www.codeproject.com/Articles/5531/Redirecting-an-arbitrary-Console-s-Input-Output

    【讨论】:

    • stackoverflow.com/questions/26398214/redirect-ftp-pipe-in-c 在这里,我更改了我的代码,它现在可以完美运行,但我遇到了与这个 OP 相同的问题。当我们在真实控制台中输入“ftp”或“wmic”时,我们会收到“ftp>”,而当我们输入像“123”这样的无效命令时,我们会收到“无效命令”。但是这种父进程和子控制台进程之间的交互操作并没有发生在我的代码或我在互联网上找到的所有重定向程序中。我下载了这个demo,运行时也出现了同样的问题
    猜你喜欢
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多