2016-01-14 4 views
0

Я закодировал два приложения C++, один - консоль, а другой - gui. Я хочу, чтобы приложение gui запускало консольное приложение и вставляло в него вход и перенаправляло вывод и ошибку и показывало их в текстовом поле.Перенаправление ввода и вывода дочернего процесса не работает

мой код не работает в GUI-приложении после нажатия кнопки запуска и не показывает вывод, и кажется, что приложение gui зависает!

вот мой код:

[консольная часть]:

#include <iostream> 
using namespace std; 

int main() 
{ 
int pass; 
//cout << "welcome message from cpp app ..." << endl; 
cout << "please enter pass => "; 
cin >> pass; 
if (pass==12345) 
    cout << "ok!" << endl; 
else 
    cout << "oops!" << endl; 
//system("pause"); 
return 0; 
} 

[гуй часть]:

#include <windows.h> 
#include <CommCtrl.h> 

#define TEXTBOX1 100 
#define BUTTON1 101 

HWND htbx = nullptr; 
HANDLE hChildStd_IN_Rd = nullptr; 
HANDLE hChildStd_IN_Wr = nullptr; 
HANDLE hChildStd_OUT_Rd = nullptr; 
HANDLE hChildStd_OUT_Wr = nullptr; 

int MessageLoop(); 

void ShowError() 
{ 
    LPVOID lpMsgBuf; 
    DWORD dw = GetLastError(); 
    DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS; 
    FormatMessage(flags, nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), LPWSTR(&lpMsgBuf), 0, nullptr); 
    MessageBox(nullptr, LPCWSTR(lpMsgBuf), L"error", MB_OK); 
    LocalFree(lpMsgBuf); 
} 
void WriteToPipe(LPCWSTR Commands2Write) 
{ 
    DWORD dwWritten; 
    bool bSuccess = false; 
    bSuccess = WriteFile(hChildStd_IN_Wr, Commands2Write, sizeof(Commands2Write), &dwWritten, nullptr); 
    if (!bSuccess) 
     ShowError(); 
    if (!CloseHandle(hChildStd_IN_Wr)) 
     ShowError(); 
} 
void ReadFromPipe() 
{ 
    DWORD dwRead; 
    LPVOID lpDataBuf[4096]; 

    if (hChildStd_OUT_Rd==INVALID_HANDLE_VALUE) 
    { 
     MessageBox(0, L"INVALID HANDLE", L"error", MB_OK); 
    } 

    //bool bSuccess = false; 
    /*bSuccess = ReadFile(hChildStd_OUT_Rd, lpDataBuf, 4096, &dwRead, nullptr); 
    if (!bSuccess) 
     ShowError();*/ 

    while (ReadFile(hChildStd_OUT_Rd, lpDataBuf, sizeof(lpDataBuf), &dwRead, nullptr)) 
    { 
     SendMessage(htbx, WM_SETTEXT, 0, LPARAM(LPCWSTR(lpDataBuf))); 
     // MessageBox(nullptr, LPCWSTR(lpDataBuf), L"Result", MB_OK); 
    } 
    LocalFree(lpDataBuf); 

} 
void Run() 
{ 
    bool bSuccess = false; 
    PROCESS_INFORMATION PI; 
    ZeroMemory(&PI, sizeof(PI)); 
    STARTUPINFO SI; 
    ZeroMemory(&SI, sizeof(SI)); 
    SI.cb = sizeof(SI); 
    SI.dwFlags = STARTF_USESTDHANDLES; 
    //SI.hStdError = hChildStd_OUT_Wr; 
    //SI.hStdOutput = hChildStd_OUT_Wr; 
    //SI.hStdInput = hChildStd_IN_Rd; 
    SI.hStdError = hChildStd_OUT_Rd; 
    SI.hStdOutput = hChildStd_OUT_Rd; 
    SI.hStdInput = hChildStd_IN_Wr; 

    SECURITY_ATTRIBUTES SA; 
    SA.nLength = sizeof(SECURITY_ATTRIBUTES); 
    SA.bInheritHandle = TRUE; 
    SA.lpSecurityDescriptor = nullptr; 

    if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &SA, 0)) 
     ShowError(); 
    if (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) 
     ShowError(); 
    if (!CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &SA, 0)) 
     ShowError(); 
    if (!SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) 
     ShowError(); 
    bSuccess = CreateProcess(L"C:\\Windows\\system32\\cmd.exe", 
     L" /c C:\\testa.exe", nullptr, nullptr, TRUE, 0, nullptr, nullptr, &SI, &PI); 

    if (!bSuccess){ ShowError(); } 
      else{CloseHandle(PI.hProcess);CloseHandle(PI.hThread);} 

     WriteToPipe(L"12345"); 
     ReadFromPipe(); 
} 
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 

    switch (Msg) 
    { 
    case WM_CREATE: 
    { 
     CreateWindowEx(0, WC_BUTTON, L"Run", WS_VISIBLE | WS_CHILD, 420, 100, 75, 35, hWnd, HMENU(BUTTON1), nullptr, nullptr); 
     htbx=CreateWindowEx(0, WC_EDIT, L"", WS_VISIBLE | WS_CHILD | WS_BORDER| ES_MULTILINE, 10, 10, 400, 300, hWnd, HMENU(TEXTBOX1), nullptr, nullptr); 
    } 
    break; 
    case WM_COMMAND: 
     { 
      switch (LOWORD(wParam)) 
      { 
      case BUTTON1: 
       Run(); 
       break; 
      default: 
       break; 
      } 
     } 
     break; 
    case WM_CLOSE: 
     DestroyWindow(hWnd); 
     break; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     break; 
    default: 
     return DefWindowProc(hWnd, Msg, wParam, lParam); 
    } 

    return 0; 
} 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviewInstance, LPSTR lpcmdline, int ncmdshow) 
{ 
    WNDCLASSEX wndexcls; 
    wndexcls.lpszClassName = L"win"; 
    wndexcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wndexcls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 
    wndexcls.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wndexcls.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1); 
    wndexcls.lpszMenuName = NULL; 
    wndexcls.style = NULL; 
    wndexcls.hInstance = hInstance; 
    wndexcls.cbSize = sizeof(WNDCLASSEX); 
    wndexcls.cbClsExtra = 0; 
    wndexcls.cbWndExtra = 0; 
    wndexcls.lpfnWndProc = WndProc; 
    RegisterClassEx(&wndexcls); 
    HWND Win_Handle = CreateWindowEx(0, L"win", L"TestApp", WS_OVERLAPPEDWINDOW, 100, 100, 640, 380, 0, 0, hInstance, 0); 
    ShowWindow(Win_Handle, SW_SHOWDEFAULT); 
    UpdateWindow(Win_Handle); 

    int exitcode; 
    exitcode = MessageLoop(); 
    return exitcode; 
} 

int MessageLoop() 
{ 
    MSG wnd_msg; 
    while (GetMessage(&wnd_msg, NULL, 0, 0)>0) 
    { 
     TranslateMessage(&wnd_msg); 
     DispatchMessage(&wnd_msg); 
    } 
    return (int)wnd_msg.wParam; 
} 

Update:

Я обновил код основанный на ответе Бармака Шемирани и используемый набор символов ANSI. но часть writetopipe не работает и в части readfrompipe, если вы используете «/ c dir» как второй параметр в CreateProcessA вместо «/ c C: \ consoleapp.exe», например, он показывает только первую строку вывода, а не общий объем производства. почему это происходит?

[обновленный код]:

#include <windows.h> 
#include <CommCtrl.h> 

#define TEXTBOX1 100 
#define BUTTON1 101 

HWND htbx = nullptr; 
HANDLE out_read = NULL; 
HANDLE out_write = NULL; 
HANDLE in_read = NULL; 
HANDLE in_write = NULL; 

int MessageLoop(); 

void ShowError() 
{ 
    LPVOID lpMsgBuf; 
    DWORD dw = GetLastError(); 
    DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS; 
    FormatMessageA(flags, nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), LPSTR(&lpMsgBuf), 0, nullptr); 
    MessageBoxA(nullptr, LPCSTR(lpMsgBuf), "error", MB_OK); 
    LocalFree(lpMsgBuf); 
} 

void WriteToPipe() 
{ 
    DWORD writecount; 
    char bufw[1024]; 
    //memset(bufw, 12345, 5); 
    strncpy_s(bufw, "12345", sizeof(bufw)); 

    if (WriteFile(in_write, bufw, sizeof(bufw), &writecount, NULL)) 
    { 
     if (!writecount) 
     { 
      ShowError(); 
     } 

    } 
    if (!CloseHandle(in_write)) 
     ShowError(); 

    LocalFree(bufw); 
} 
void ReadFromPipe() 
{ 
    DWORD readCount; 
    char bufr[1024]; 
    memset(bufr, 0, sizeof(bufr)); 
    if (ReadFile(out_read, bufr, sizeof(bufr), &readCount, NULL)) 
    { 
     if (readCount) 
     { 
      SendMessageA(htbx, EM_SETSEL, WPARAM(-1), LPARAM(-1)); 
      SendMessageA(htbx, EM_REPLACESEL, 0, LPARAM(bufr)); 
     } 
    } 
    if (!CloseHandle(out_read)) 
     ShowError(); 

    LocalFree(bufr); 
} 
DWORD WINAPI run(LPVOID) 
{ 
    PROCESS_INFORMATION pi{}; 
    STARTUPINFOA si{ sizeof STARTUPINFO }; 
    si.dwFlags = STARTF_USESTDHANDLES; 

    { //set handles 

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

     if (!CreatePipe(&out_read, &out_write, &secAttr, 0)) ShowError(); 
     if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) ShowError(); 
     if (!CreatePipe(&in_read, &in_write, &secAttr, 0)) ShowError(); 
     if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) ShowError(); 

     si.hStdOutput = out_write; 
     si.hStdError = out_write; 
     si.hStdInput = in_read; 
     si.dwFlags |= STARTF_USESTDHANDLES; 
    } 

    if (!CreateProcessA("C:\\Windows\\system32\\cmd.exe", 
     "/c C:\\consoleapp.exe", 0, 0, TRUE, 0, 0, 0, &si, &pi)) 
     ShowError(); 

    while (pi.hProcess && WaitForSingleObject(pi.hProcess, 25) == WAIT_TIMEOUT) 
    { 
     if (out_read == INVALID_HANDLE_VALUE) 
      ShowError(); 
     if (in_write == INVALID_HANDLE_VALUE) 
      ShowError(); 

     WriteToPipe(); 
     ReadFromPipe(); 
    } 

    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 

    return 0; 
} 

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (Msg) 
    { 
    case WM_CREATE: 
    { 
     CreateWindowExA(0, WC_BUTTONA, "Run", WS_VISIBLE | WS_CHILD, 420, 100, 75, 35, hWnd, HMENU(BUTTON1), nullptr, nullptr); 
     htbx=CreateWindowExA(0, WC_EDITA, "", WS_VISIBLE | WS_CHILD | WS_BORDER| ES_MULTILINE, 10, 10, 400, 300, hWnd, HMENU(TEXTBOX1), nullptr, nullptr); 
    } 
    break; 
    case WM_COMMAND: 
     { 
      switch (LOWORD(wParam)) 
      { 
      case BUTTON1: 
       //Run(); 
       CreateThread(NULL, 0, run, 0, 0, NULL); 
       break; 
      default: 
       break; 
      } 
     } 
     break; 
    case WM_CLOSE: 
     DestroyWindow(hWnd); 
     break; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     break; 
    default: 
     return DefWindowProc(hWnd, Msg, wParam, lParam); 
    } 
    return 0; 
} 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviewInstance, LPSTR lpcmdline, int ncmdshow) 
{ 
    WNDCLASSEXA wndexcls; 
    wndexcls.lpszClassName = "win"; 
    wndexcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wndexcls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 
    wndexcls.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wndexcls.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1); 
    wndexcls.lpszMenuName = NULL; 
    wndexcls.style = NULL; 
    wndexcls.hInstance = hInstance; 
    wndexcls.cbSize = sizeof(WNDCLASSEX); 
    wndexcls.cbClsExtra = 0; 
    wndexcls.cbWndExtra = 0; 
    wndexcls.lpfnWndProc = WndProc; 
    RegisterClassExA(&wndexcls); 
    HWND Win_Handle = CreateWindowExA(0, "win", "TestApp", WS_OVERLAPPEDWINDOW, 100, 100, 640, 380, 0, 0, hInstance, 0); 
    ShowWindow(Win_Handle, SW_SHOWDEFAULT); 
    UpdateWindow(Win_Handle); 
    int exitcode; 
    exitcode = MessageLoop(); 
    return exitcode; 
} 

int MessageLoop() 
{ 
    MSG wnd_msg; 
    while (GetMessage(&wnd_msg, NULL, 0, 0)>0) 
    { 
     TranslateMessage(&wnd_msg); 
     DispatchMessage(&wnd_msg); 
    } 
    return (int)wnd_msg.wParam; 
} 
+1

'Run()' называется синхронно из вашего обработчика. Никакие другие сообщения не отправляются, пока 'Run()' не вернется. Сюда входят сообщения, отправленные в элемент управления Edit, поэтому он не будет обновляться. Вам нужно получить книгу, чтобы понять структуру приложения GUI на основе событий. [Программирование Windows®, пятое издание] (http://www.amazon.com/dp/157231995X) Чарльзом Петцольдом - это золотой стандарт для программирования Windows API. – IInspectable

+0

Переместить 'Run()' в рабочий поток. Вы можете использовать 'SendMessage()' в нем, и теперь основной поток будет иметь возможность обрабатывать эти сообщения, а также системные сообщения, например, для рисования пользовательского интерфейса и т. Д. –

+0

@RemyLebeau: спасибо за вашу помощь. – BlueFlower

ответ

1

Я не уверен, если это имеет смысл перенаправить ввод и вывод для окна консоли. Если это предназначено для упражнений, я показал более простой пример для перенаправления вывода консоли.

Консольная программа, по-видимому, ANSI, а программа Windows - UNICODE. Эта часть запутывает, вам нужно использовать ANSI API в некоторых местах.

DWORD WINAPI run(LPVOID) 
{ 
    HANDLE out_read = NULL; 
    HANDLE out_write = NULL; 

    PROCESS_INFORMATION pi{}; 
    STARTUPINFO si{ sizeof STARTUPINFO }; 
    si.dwFlags = STARTF_USESTDHANDLES; 

    { //set handles 

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

     if (!CreatePipe(&out_read, &out_write, &secAttr, 0)) error(); 
     if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) error(); 

     si.hStdOutput = out_write; 
     si.dwFlags |= STARTF_USESTDHANDLES; 
    } 

    if (!CreateProcess(L"consoleProgram.exe", 0, 0, 0, TRUE, 0, 0, 0, &si, &pi)) 
     error(); 

    while (pi.hProcess && WaitForSingleObject(pi.hProcess, 25) == WAIT_TIMEOUT) 
    { 
     if (out_read == INVALID_HANDLE_VALUE) 
      break; 

     DWORD readCount; 
     char buf[1024]; 
     memset(buf, 0, sizeof buf); 
     if (ReadFile(out_read, buf, sizeof(buf), &readCount, NULL)) 
     { 
      if (readCount) 
      { 
       SendMessageA(hedit, EM_SETSEL, WPARAM(-1), LPARAM(-1)); 
       SendMessageA(hedit, EM_REPLACESEL, 0, (LPARAM)buf); 
      } 
     } 
    } 

    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 

    return 0; 
} 

LRESULT CALLBACK WndProc(...) 
{ 
    ... 
    case WM_COMMAND: 
     switch (LOWORD(wParam)) 
      case BUTTON1: 
       CreateThread(NULL, 0, run, 0, 0, NULL); 
      ... 
} 
+0

Спасибо за помощь, +1 UpVote для вас. я обновил код на основе вашего ответа, но часть чтения и записи должна быть исправлена. – BlueFlower

+0

Этот код работал, он перенаправлял консольный ввод в Windows. Я протестировал его. Но вы сломали его, вероятно, хуже, чем раньше. Вы не можете просто вставлять код, не понимая, что он делает. Не имеет смысла перенаправлять как входные, так и выходные. В лучшем случае консольное окно сидит там как черный экран, но, скорее всего, программа выйдет из строя. Также нет причин использовать '' c: \\ windows \\ system32 \\ cmd.exe ''. Windows может быть установлена ​​в другой каталог ... –

+0

Я знаю, что Windows может быть установлена ​​в другой каталог. «c: \\ windows \\ system32 \\ cmd.exe» для eaxmple. вы сказали: «Этот код работал», но, как я сказал в превью. комментарий, чтение и запись должны быть исправлены. по этой причине я показал такой пример, как «c: \\ windows \\ system32 \\ cmd.exe» и «/ c dir» в качестве аргумента, и хочу показать, что он не перенаправляет вывод должным образом. Конечно, он перенаправляет вывод для consoleapp.exe правильно (спасибо за вашу помощь, +1 UpVote для вас), но не для любого консольного приложения, например командной строки Windows. – BlueFlower

Смежные вопросы