popoff Опубликовано 17 января, 2008 Жалоба Опубликовано 17 января, 2008 Есть консольное приложение - TurboProlog.Хочу написать виндовый гуй для него. Так как отдельного комипилятора, интерпретатора TurboProlog'а нету, то думаю сделать так - использовать prolog.exe таким образом, чтобы вывод с консоли происходил, например в Memo на моей форме, а, например, по нажатию кнопки на форме, текст из Memo вставлялся в консоль, начиналась бы компияция, а результат опять из консоли в мое приложение.Это вообще реально?
0xDEADBEEF Опубликовано 17 января, 2008 Жалоба Опубликовано 17 января, 2008 Классиеская модель Front-End Back-End. Основные функции приложения - Back, и множество пользовательских GUI - Front. На ней построенно большенство приложений в Linux.Как перенаправить? Можно попробовать API функции ReadFile/WriteFile и читать из stdin/stdout (соответствущие макросы для них есть), потом вставлять в Memo.А вот если погуглить, то можно найти и более изящное решение
popoff Опубликовано 17 января, 2008 Автор Жалоба Опубликовано 17 января, 2008 Классиеская модель Front-End Back-End. Основные функции приложения - Back, и множество пользовательских GUI - Front. На ней построенно большенство приложений в Linux.Как перенаправить? Можно попробовать API функции ReadFile/WriteFile и читать из stdin/stdout (соответствущие макросы для них есть), потом вставлять в Memo.А вот если погуглить, то можно найти и более изящное решение да гуглил я полночи. про переназначение ввода/вывода консоли есть, но очень мало. ссылки три всего нашел, где действительно это обсуждается. нашел 2 примера. один ваще на дельфях. переделал на С++ - не работает. второй пример работает только с cmd. там в обоих примерах пайпы какието.. я первый раз про них слышу поэтому не очень понимаю чоэт такое.кароч тоесть вообще можно сделать так, чтоб сохранялась полная функциональность консольного приложения такого, как TurboProlog или TurboC?читаю щас в справке про stdin/stdout, нашел тему Creating a Child Process with Redirected Input and Output. нашел как используетсяReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);читаю. но всеравно пока ничо непонятно. слава богу хоть на английском справка, а то как-то раз пришлось искать ответ на французском форуме)Добавлено спустя 24 минуты 46 секунд:по справке смог сделать только это:#include #include #include #pragma hdrstop#pragma argsused#define BUFSIZE 4096HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hInputFile, hSaveStdin, hSaveStdout;BOOL CreateChildProcess(VOID);unsigned long __stdcall WriteToPipe(VOID *p);unsigned long __stdcall ReadFromPipe(VOID *p);VOID ErrorExit(LPTSTR);VOID ErrMsg(LPTSTR, BOOL);int main(int argc, char* argv[]){ SECURITY_ATTRIBUTES saAttr; BOOL fSuccess;// Set the bInheritHandle flag so pipe handles are inherited. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // The steps for redirecting child process's STDOUT: // 1. Save current STDOUT, to be restored later. // 2. Create anonymous pipe to be STDOUT for child process. // 3. Set STDOUT of the parent process to be write handle of // the pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the read handle and // close the inheritable read handle.// Save the handle to the current STDOUT. hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);// Create a pipe for the child process's STDOUT. if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) ErrorExit("Stdout pipe creation failed\n");// Set a write handle to the pipe to be STDOUT. if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) ErrorExit("Redirecting STDOUT failed");// Create noninheritable read handle and close the inheritable read// handle. fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup , 0, FALSE, DUPLICATE_SAME_ACCESS); if( !fSuccess ) ErrorExit("DuplicateHandle failed"); CloseHandle(hChildStdoutRd); // The steps for redirecting child process's STDIN: // 1. Save current STDIN, to be restored later. // 2. Create anonymous pipe to be STDIN for child process. // 3. Set STDIN of the parent to be the read handle of the // pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the write handle, // and close the inheritable write handle.// Save the handle to the current STDIN. hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);// Create a pipe for the child process's STDIN. if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) ErrorExit("Stdin pipe creation failed\n");// Set a read handle to the pipe to be STDIN. if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) ErrorExit("Redirecting Stdin failed");// Duplicate the write handle to the pipe so it is not inherited. fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, // not inherited DUPLICATE_SAME_ACCESS); if (! fSuccess) ErrorExit("DuplicateHandle failed"); CloseHandle(hChildStdinWr);// Now create the child process. if (! CreateChildProcess()) ErrorExit("Create process failed");// After process creation, restore the saved STDIN and STDOUT. if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) ErrorExit("Re-redirecting Stdin failed\n"); if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) ErrorExit("Re-redirecting Stdout failed\n");// Get a handle to the parent's input file. if (argc > 1) hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); else hInputFile = hSaveStdin; if (hInputFile == INVALID_HANDLE_VALUE) ErrorExit("no input file\n");// Write to pipe that is the standard input for a child process. //WriteToPipe(); CreateThread( 0, 0, WriteToPipe, 0, 0, 0 );// Read from pipe that is the standard output for child process. //ReadFromPipe(); CreateThread( 0, 0, ReadFromPipe, 0, 0, 0 ); return 0;}BOOL CreateChildProcess(){ PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo;// Set up members of STARTUPINFO structure. ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO);// Create the child process. return CreateProcess(NULL, "c:\\prolog\\prolog.exe", // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION}unsigned long __stdcall WriteToPipe(void *p){ DWORD dwRead, dwWritten; CHAR chBuf[BUFSIZE];// Read from a file and write its contents to a pipe. for (; { if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) break; if (! WriteFile(hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL)) break; }// Close the pipe handle so the child process stops reading. if (! CloseHandle(hChildStdinWrDup)) ErrorExit("Close pipe failed\n");}unsigned long __stdcall ReadFromPipe(VOID *p){ DWORD dwRead, dwWritten; CHAR chBuf[BUFSIZE]; HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);// Close the write end of the pipe before reading from the// read end of the pipe. if (!CloseHandle(hChildStdoutWr)) ErrorExit("Closing handle failed");// Read output from the child process, and write to parent's STDOUT. for (; { if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) break; if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL)) break; }}VOID ErrorExit (LPTSTR lpszMessage){ fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0);}//---------------------------------------------------------------------------работает, но это ведь просто то же самое получается. просто в моей консоли открывается та же самая консольная программа. типа клон)как к VCL-то это дело прикрутить? там нету этого.
0xDEADBEEF Опубликовано 17 января, 2008 Жалоба Опубликовано 17 января, 2008 Великий и ужасный виндовый АПИ *24Pipe - эта такая сущность для межпроцессорного взаимодействия, действует как двунаправленная труба (по принципу FIFO), читать/писать как из обычного файла. (подробнее - Основы операционных систем)А работает сей код так:1. Запоминаем дескрипторы стандартного I/O2. Делаем пайпы. Перенапавляем стандартный I/O в них3. Клонируем нужные дескрипторы для предотвращения наследования их дочерним процессом, ненужные закрываем.4. Пораждаем процесс. Здесь основная фишка: теперь вместо консоли он пишет/читает в пайп, а мы можем писать/читать из них. hChildStdoutRdDup - дескрипотр для чтения с STDOUT предка, hChildStdinWrDup - для записи в STDIN предка.5. Далее создание инфраструктуры для избежания блокировок - это потоки исполнения (Thread)Вот и вся канитель. ReadFromPipe/WriteToPipe дописываем/обворачиваем как нам надо, пишем парсер (если надо) и вперед на ГУИ!P.S. Настоятельно рекоммендую хорошенько проштудировать тему многопоточного программирования, в частности синхронизацию. Это позволит избежать труднотлавливамых спецэффических багов.
popoff Опубликовано 18 января, 2008 Автор Жалоба Опубликовано 18 января, 2008 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hInputFile, hSaveStdin, hSaveStdout; BOOL CreateChildProcess(AnsiString command); unsigned long __stdcall ReadFromPipe(void*p); const BUFSIZE = 2048; AnsiString TMainForm :: make_console( AnsiString command ) { AnsiString ret = "success"; SECURITY_ATTRIBUTES saAttr; BOOL fSuccess; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { return "Stdout pipe creation failed"; } if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) { return "Redirecting STDOUT failed"; } fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup , 0, FALSE, DUPLICATE_SAME_ACCESS); if( !fSuccess ) { return "DuplicateHandle failed"; } CloseHandle(hChildStdoutRd); hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { return "Stdin pipe creation failed"; } if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) { return "Redirecting Stdin failed"; } fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS); if (! fSuccess) { return "DuplicateHandle failed"; } CloseHandle(hChildStdinWr); if(! CreateChildProcess( command )) { return "Create process failed"; } if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) { return "Re-redirecting Stdin failed"; } if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) { return "Re-redirecting Stdout failed"; } hInputFile = hSaveStdin; if (hInputFile == INVALID_HANDLE_VALUE) { return "no input file"; } CreateThread( 0, 0,ReadFromPipe, 0, 0, 0); return ret; }//--------------------------------------------------------------------------- BOOL CreateChildProcess( AnsiString command ) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.dwFlags = STARTF_USESHOWWINDOW; //??? ???! siStartInfo.wShowWindow = SW_HIDE; //??? ???! return CreateProcess(NULL, //command.c_str(), // command line "cmd", NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION }//--------------------------------------------------------------------------- unsigned long __stdcall ReadFromPipe(void*p) { DWORD dwRead, dwWritten; CHAR chBuf[BUFSIZE]; HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (!CloseHandle(hChildStdoutWr)) return 0; //return "Closing handle failed"; for (; { if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) break; if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL)) break; MainForm->DialogMemo->Lines->Add( chBuf ); } }
The_Ice Опубликовано 18 января, 2008 Жалоба Опубликовано 18 января, 2008 unsigned long __stdcall ReadFromPipe(void*p) { DWORD dwRead, dwWritten; CHAR chBuf[bUFSIZE]; HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (!CloseHandle(hChildStdoutWr)) return 0; //return "Closing handle failed"; for (; { if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) break; if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL)) break; MainForm->DialogMemo->Lines->Add( chBuf ); } }что то забыл?
popoff Опубликовано 18 января, 2008 Автор Жалоба Опубликовано 18 января, 2008 делаю короче так: STARTUPINFO si; char buf[1024],bufin[1024]; DWORD i2,i3; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; HANDLE cstdin, wstdin, rstdout, cstdout; unsigned long __stdcall DO(void *p) { for(; { BOOL read=TRUE; while (read == TRUE) { memset(buf,0,1024); ReadFile(rstdout,buf,1024,&i2,0); read = (i2 == 1024); MainForm->DialogMemo->Lines->Add( buf ); } } }//--------------------------------------------------------------------------- AnsiString TMainForm :: make_console( AnsiString command ) { AnsiString ret = ""; sa.lpSecurityDescriptor = NULL; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(STARTUPINFO); GetStartupInfoA(&si); CreatePipe(&cstdin, &wstdin, &sa, 0); CreatePipe(&rstdout, &cstdout, &sa, 0); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = FALSE; si.hStdOutput = cstdout; si.hStdError = cstdout; si.hStdInput = cstdin; CreateProcess( NULL, "cmd", 0, 0, TRUE, CREATE_NEW_CONSOLE, NULL,NULL,&si,π); CreateThread(0,0,DO,0,0,0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); DialogMemo->Lines->Add(GetLastError()); return ret; }все работает. текст из консоли CMD попадает в DialogMemo. но когда в CreateProcess запускаю не cmd, а, скажем bc.exe (BorlandC), то CreateProcess кажет ошибку 126(The specified module could not be found). Причем если убрать всю эту фигню с подменой потоков, то CreateProcess работает нормально и правильно даже на bc.exe.В чем дело? может потомуш cmd.exe 32-х разрадный, а bc.exe 16-ти?
popoff Опубликовано 19 января, 2008 Автор Жалоба Опубликовано 19 января, 2008 ВСЕ ПОНЯЛ!Дело в том, что в некоторых случаях, некоторые 16-битные программы под 9x, 2000 (но не NT) некорректно закрывают консоль. И ReadFile при попытке чтения возвращает ошибку и пустой буфер.Если вы работает под NT-family, просто вызвайте вашу программу через CMD. Т.е. используйте командную строку типа:cmd.exe /c myprog.exeВ данном случае, CMD.EXE и поработает тем самым stub'ом, т.е. примет и воспроизведет консольный вывод и корректно все закроет.Все работает.
Рекомендуемые сообщения
Пожалуйста, войдите, чтобы комментировать
Вы сможете оставить комментарий после входа в
Войти