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'ом, т.е. примет и воспроизведет консольный вывод и корректно все закроет.Все работает. Ссылка на комментарий
Рекомендуемые сообщения
Пожалуйста, войдите, чтобы комментировать
Вы сможете оставить комментарий после входа в
Войти