консоль в окне под win32

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
nagash
новенький
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05
Контактная информация:

консоль в окне под win32

Сообщение nagash »

Такая проблема... Нужно облагородить консоль) Т.е. идея - создать окно, а в нем нечто вроде консоли, как отдельный элемент.
К сожалению моих познаний в программировании не хватает, недавно только перешел на fpc с обычного паскаля. Все что я смог - создать пустое окошко с надписью 'Hello world!')
Помогите пожалуйста, просьба не тыкать в мануалы - мне нужно решение конкретной проблемы, а не умение работать с окнами.
Спасибо :)
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Интересная задачка, тоже над ней как-то думал. Даже что-то пытался написать (на Dephi), но опыт был не очень удачный.

http://the1st.adygnet.ru/~ftp/pub/examp ... /Mycmd.zip

Единственное, что приходит на ум, так это написать с нуля свой элемент управления, хотя можно по-пробовать развить мой старый пример. Там основная проблема с перенаправлением ввода-вывода (его нужно полностью переделать, о том как см. http://freepascal.ru/forum/viewtopic.php?t=2311 ), скорее всего есть еще какие проблемы - давно писал не помню
nagash
новенький
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05
Контактная информация:

Сообщение nagash »

Спасибо за инфу, гляну вечером.
Ммм.... думал что все это проще сделать) По-моему в моем случае проще забить на консоль и переписать программу целиком под винду. А так я просто хотел совместить консольный вариант с кнопочным интерфейсом...
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

nagash писал(а):А так я просто хотел совместить консольный вариант с кнопочным интерфейсом...

Ну если так, то все действительно просто. Под Windows нужно просто заменить директиву {$APPTYPE GUI} на {$APPTYPE CONSOLE} и кроме окошек будет висеть консоль. Так же под Windows можно использовать WinAPI: AllocConsole|FreeConsole

Под *nix вообще нет явного деления на конные и консольные программы, можно спокойно использовать и то и другое.

Но обычно делаться консольная утилита и к ней граф интерфейс. Или делается библиотека, а ее использует оконное приложение и консольное..
nagash
новенький
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05
Контактная информация:

Сообщение nagash »

shade писал(а):Под Windows нужно просто заменить директиву {$APPTYPE GUI} на {$APPTYPE CONSOLE}


Я немного не так выразился. Мне нужно чтобы вывод консоли был частью интерфейса окна, т.е. как раз то, о чем написано выше :roll:
Щас глянул Mycmd.zip. Без ста грамм не разберусь, опыта не хватает(
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

nagash писал(а):Щас глянул Mycmd.zip. Без ста грамм не разберусь, опыта не хватает(

Тут нужно не только 100 грамм, но и справочник по WinAPI

Уточню:
1. тебе нужно только выводить, а вводить не надо.
2. хочеться использовать обычные write/writeln и отображать их вывод на отдельном элементе напоминающем консоль.

Если так, то:

Насчет первого пункта, в качестве такого элемента можно использовать TMemo, а можно TPaintBox, но на нем самостоятельно все отрисовывать, что в общем не сложно. Можно, конечно и свой компонент написать.

Насчет второго пункта:
1. написать класс производный от TStream
2. в нем определить метод Write - он будет получать выводимый текст.
3. подключить модуль streamio из FCL
4. Сделать Assign(output, MyStream), где MyStream - экземпляр твоего класса созданного в п.1
5. Rewrite(output);
Потом можно writeln('Привет мир!');
:wink:
Аватара пользователя
bw
постоялец
Сообщения: 359
Зарегистрирован: 01.12.2005 10:36:23
Откуда: Усть-Илимск
Контактная информация:

Сообщение bw »

4. Сделать Assign(output, MyStream), где MyStream - экземпляр твоего класса созданного в п.1
5. Rewrite(output);

Аналогичные действия проделываются системной процедурой SysInitStdIO. Причем текие переменные как Input и Output являются потоконезависимыми и хотя их значения копируются при "дублировании" потока, нужно учесть что для каждого потока будет вызываться SysInitStdIO и эти переменные будут переопределяться. Так что для каждого нового потока необходимо заново ассигновать эти переменные. Так же нужно учитывать, что при завершении потока эти переменные "закрываются", а может и нет, точно не помню.
Смотрите RTL для подробностей.

..bw
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

bw писал(а):Так же нужно учитывать, что при завершении потока эти переменные "закрываются", а может и нет, точно не помню.

Закрытие файлов по завершении, миф распространяемый почти всеми (а может и всеми) учебниками. Об input/output/stderr system сам позаботиться, а то, что открываете вы, вы же и должны закрыть.

bw писал(а):Аналогичные действия проделываются системной процедурой SysInitStdIO

Аналогичные, но иные. Я усомнился, в том, что они вызываются для каждого нового потока и проверил - действительно открываются, но другим методом, отличным от обычного Assign/Reset/Rewrite.

Возможно для каких-то систем и нужно открывать файлы стандартного ввода-вывода для каждого потока, но для обычных Assign/Reset/Rewrite этого делать не нужно. Дело в том, что тип Text по сути обычная структура и Assign просто заполняет поля в этой структуре, и соответственно, если вызвать Assign до закрытия файла, то мы просто потеряем файловый дескриптор.

Например,

Код: Выделить всё

uses sysutils;

var f: Text;
begin
  Assign(f, 'output.txt');
  Rewrite(f);
  writeln('Hello world');
  // не закрывая f, создаем новое связывание с тем же файлом
  Assign(f, 'output.txt');
  Rewrite(f); // <- здесь мы получим ошибку, потому что хотим
              // открыть файл который еще заблокирован
  writeln('we never reach this line');
  writeln(f, 'Hello again');
end.
Аватара пользователя
bw
постоялец
Сообщения: 359
Зарегистрирован: 01.12.2005 10:36:23
Откуда: Усть-Илимск
Контактная информация:

Сообщение bw »

Про закрытие точно не скажу, по крайне мере это было бы логично, с моей точки зрения.
Аналогичные, но иные. Я усомнился, в том, что они вызываются для каждого нового потока и проверил - действительно открываются, но другим методом, отличным от обычного Assign/Reset/Rewrite.
Как же иным, точно таким же, вызовом SysInitStdIO, а последний что вызывает, зависит только от реализации RTL для конкретной ОС. Вообще нет прямой необходимости вызывать ни одину из этих процедур (тут ты прав), главное инициализировать объекты Text (Input, Output).
Например я это делаю так (в своей реализации SysInitStdIO и системного IO):

Код: Выделить всё

TextRec(f).InOutFunc := @WriteStdout;
TextRec(f).FlushFunc := @WriteStdout;
TextRec(f).CloseFunc := @CloseStdout;

Так же, при завершении программы, я вызываю Close для Input и Output, хотя реализация этих моих потоковых устройств, не требует закрытия, т.е. CloseStdout, например, у меня реализован так:

Код: Выделить всё

procedure CloseStdout(var f: TextRec);
begin
end;

Хотя тут мы говорим об одном и том же.
Но я считаю что закрывать все же нужно. Ты не знаешь какая реализация скрывается за этой структурой.

..bw
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

В контексте данной задачи, все это излишне, поправьте если ошибаюсь.

Нам ведь не нужно свою RTL писать, а правильно заюзать имеющуюся - поэтому достаточно просто Assign(output, MyStream); Rewrite(output); В конце для надежности можно сделать Close(output), но в этом нет большой необходимости, т.к. во-1-х мы выводим не на устройство хранения, а на экран, во-2-х RTL сама закроет output при выходе (а если и не закроет - в случае $APPTYPE GUI, то не страшно).

Можно для уверенности не использовать output, а использовать свою переменную, например myout: Text;
Assign(myout, MyStream);
Rewrite(myout);
writeln(myout, 'Hello world');

А в конце сделать Close(myout); MyStream.Free;

Я бы все это дело вынес бы в отдельный юнит и использовал бы секции инициализации/финализации

Код: Выделить всё

initialization
  MyStream := TMyStream.Create;
  Assign(myout, MyStream);
  Rewrite(myout);

finalization
  Close(myout);
  MyStream.Free;

end.


или события OnCreate/OnDestroy окна на котором планируется выводить консоль
nagash
новенький
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05
Контактная информация:

Сообщение nagash »

2 shade
Да, это именно то, что мне нужно. Принцип понятен.


Спасибо всем, буду пытаться разобраться, но все-таки склоняюсь к выводу, что гораздо проще все переписать с нуля под винду, чем лезть в такие дебри, в которых я пока что практически ничего не понимаю)

Да и программка простая слишком, чтобы из-за нее так париться)
http://ifolder.ru/2089926
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

nagash писал(а):Да и программка простая слишком, чтобы из-за нее так париться)

Понятно, тут просто одну формочку на lazarus сделать и никакой консоли не нужно.

А вообще идея задела за живое, может на недельке напишу компонент :D
nagash
новенький
Сообщения: 50
Зарегистрирован: 21.05.2007 08:27:05
Контактная информация:

Сообщение nagash »

shade писал(а):Понятно, тут просто одну формочку на lazarus сделать и никакой консоли не нужно.

Нема у меня лазаруса) А траф дорогой...

shade писал(а):А вообще идея задела за живое, может на недельке напишу компонент

Отпишись плиз тут, если напишешь. Интересно было бы разобраться.
Ответить