[c ++管道重定向与CreateProcess()问题

问题描述 投票:0回答:1

我正在尝试制作一个远程管理员工具,以便可以控制家用计算机,并使服务器正常工作。我可以很好地通过网络发送命令,但是在cmd中执行命令时遇到麻烦。我试图使用CreateProcess()函数启动cmd,然后通过管道写入命令并读取结果。我想多次执行此操作而不关闭cmd,以便可以使用cd等。

似乎至少部分起作用,因为在调用startCmd()函数时,它将为cmd打印欢迎消息。但是,在此之后,当我尝试将命令写入cmd时,它永远不会给我任何输出。当我检查out管道时,它说它已读取0个字节,但首次启动时除外。

这是否意味着我只能执行1条命令,或者在使用一次后是否需要以某种方式操纵管道,或者类似的东西?另外,如果代码太草率,我也表示歉意,我刚刚尝试了许多不同的解决方案,并且我一直没有担心代码的整洁度。

#define BUFSIZE 4096
#define PATHMAX 400

bool running = false;

HANDLE hChildStdInR = NULL;
HANDLE hChildStdInW = NULL;
HANDLE hChildStdOutR = NULL;
HANDLE hChildStdOutW = NULL;

PROCESS_INFORMATION piProcInfo;

void ErrorExit(const char*);

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

    // Create a pipe for the child process's STDOUT. 
    if (!CreatePipe(&hChildStdOutR, &hChildStdOutW, &saAttr, 0))
        ErrorExit("StdoutRd CreatePipe");

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(hChildStdOutR, HANDLE_FLAG_INHERIT, 0))
        ErrorExit("Stdout SetHandleInformation");

    // Create a pipe for the child process's STDIN. 
    if (!CreatePipe(&hChildStdInR, &hChildStdInW, &saAttr, 0))
        ErrorExit("Stdin CreatePipe");

    // Ensure the write handle to the pipe for STDIN is not inherited. 
    if (!SetHandleInformation(hChildStdInW, HANDLE_FLAG_INHERIT, 0))
        ErrorExit("Stdin SetHandleInformation");

    char cmdPath[PATHMAX];
    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 = hChildStdOutW;
    siStartInfo.hStdOutput = hChildStdOutW;
    siStartInfo.hStdInput = hChildStdInR;
    siStartInfo.wShowWindow = SW_HIDE;
    siStartInfo.dwFlags |= STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    GetEnvironmentVariableA("ComSpec", cmdPath, sizeof(cmdPath));

    // Create the child process. 
    bSuccess = CreateProcess(
        cmdPath,
        NULL,     // command line (NULL because application itsself is cmd)
        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

    // Close un-needed pipes
    /*CloseHandle(hChildStdOutW);
    CloseHandle(hChildStdInR);*/    // Doesn't change anything why I uncomment these lines

    // If an error occurs, exit the application. 
    if (!bSuccess)
        ErrorExit("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. 
        /*CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);*/
    }

    return true;
}

bool writeToCmd(const string& s)
{
    DWORD dwWritten;
    const char* cmd = s.c_str();
    return WriteFile(hChildStdInW, cmd, sizeof(cmd), &dwWritten, NULL);
}

bool exec(const string& command)
{
    if (!writeToCmd(command)) {
        return false;
    }
    else {
        cout << "Succesfully Wrote" << endl;
    }
    return true;
}

void checkPipe()
{
    while (running) {
        while (1) {
            Sleep(50);
            DWORD bytesAvail = 0;
            if (!PeekNamedPipe(hChildStdOutR, NULL, 0, NULL, &bytesAvail, NULL)) {
                cout << "Failed to call PeekNamedPipe" << endl;
            }
            if (bytesAvail) {
                CHAR buf[BUFSIZE];
                DWORD n;
                BOOL success = ReadFile(hChildStdOutR, buf, BUFSIZE, &n, NULL);
                if (!success || n == 0) {
                    cout << "Failed to call ReadFile" << endl;
                    break;
                }
                string s = string(buf, buf + n);
                cout << s << endl;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2) {
        cout << "Usage: " << argv[0] << " <ADRESS>" << endl;
        return 1;
    }

    ClientSocket client(argv[1], DEFAULT_PORT);

    // Wait for initial response
    string w = client.recieveLine();

    if (w == "welcome") {
        cout << "Connection Successful! " << endl;
    }

    running = true;

    if (startCmd()) cout << "Cmd Started" << endl;
    thread checkLoop(&checkPipe);

    while (true) {
        vector<string> command = split(client.recieveLine());
        if (command[0] == "run") {
            exec(command[1]);
        }
        else if (command[0] == "exit") {
            running = false;
            client.sendLine("exit");
            break;
        }
    }

    if (!CloseHandle(hChildStdInW))
        ErrorExit("StdInWr CloseHandle");

    checkLoop.join();
    client.close();

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

    return 0;
}
c++ pipe remote-access readfile createprocess
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.