Переадресация канала c ++ с помощью CreateProcess () - PullRequest
1 голос
/ 27 октября 2019

Я пытаюсь создать инструмент удаленного администратора, чтобы я мог управлять своим домашним компьютером, и у меня работает сервер. Я могу отправлять команды по сети нормально, но у меня возникают проблемы с их выполнением в cmd. Я попытался использовать функцию CreateProcess (), чтобы запустить cmd, а затем написать команды через канал и прочитать результат. Я хотел бы сделать это несколько раз, не закрывая cmd, чтобы я мог использовать cd и т. Д.

Кажется, что он хотя бы частично работает, потому что он выводит приветственное сообщение для cmd, когда startCmd() функция вызывается. Однако после этого, когда я пытаюсь писать команды в cmd, он никогда не выдает никаких результатов. Когда я проверяю выходной канал, он говорит, что он прочитал 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;
}
...