Aplikacje konsolowe

Adam Boduch

Pewnie kiedyś spotkaliście się z określeniem: aplikacja konsolowa. Jeżeli nie to wyjaśniam: jest to aplikacja uruchamiana w okienku MS - DOS. Taka opcja nadaje się do pisania prostych programów, które mają być wyświetlane w okienku DOSa. Żeby aplikacja działała w trybie okienkowym DOSa w kodzie programu musisz umieścić taką dyrektywę:

{$APPTYPE CONSOLE} // <-- aplikacja bedzie konsolowa

Jeżeli masz otwarte Delphi to zamknij formularz, a następnie edytor kodu. Z menu Project wybierz View Source. Wyświetli Ci się zawartość pliku DPR. Usuń tekst tak aby na górze pozostała nazwa programu ( pierwsza linia - słowo kluczowe program ). Pozostaw także linie begin i end ( end z kropką ). OK - teraz możesz zapisać swój projekt (ja zapisałem pod nazwą console). Dodaj dyrektywę {$APPTYPE CONSOLE}. Napisz słowo uses i po nim dodaj nazwę modułu, który będzie włączony do aplikacji - moduł Windows. Nasz program na tym etapie powinien wyglądać tak:

program console;    

{$APPTYPE CONSOLE} // <-- aplikacja bedzie konsolowa

uses Windows;

begin

end.

Właściwy kod programu umieszcza się pomiędzy linie Begin i End.

Napiszemy program, który będzie się opierał na oknie DOS i będzie zajmował mało miejsca na dysku. Będzie to instalator :) Zanim jednak zaczniemy należy wyjaśnić parę podstawowych rzeczy. Wyświetlenie tekstu w okienku następuje za pomocą procedury Writeln. Jeżeli więc chcesz wyświetlić jakiś tekst piszesz:

Writeln('To jest tekst');

Jeżeli jednak uruchomisz program z tak wpisanym kodem to otworzy się okienko na sekundę, wyświetli tekst, a następnie zniknie. Żeby okno było przez cały czas otwarte możesz zastosować komendę Readln. Powoduje to, że program czeka na odpowiedź użytkownika i kontynuuje pracę po naciśnięciu przycisku ENTER. Readln może także służyć do pobierania tekstu wpisanego przez użytkownika - np:

var
  Dir: String;
begin
  Readln(Dir);

Zmienna Dir zawiera tekst wpisany przez użytkownika.

Zanim zaczniemy pracę nad programem musisz stworzyć plik zasobów z plikami, które będą instalowane. W moim wypadku będą to pliki graficzne. Jak dodać takie pliki do zasobów - opisałem w artykule Instalator.

Gdy już masz gotowy w programie umieść tablicę, która będzie zawierała nazwy plików umieszczonych w zasobie. W moim wypadku taka tablica wyglądała tak:

const
{  tablica plikow, ktore sa wlaczone do zasobow }
  Files : array[0..6] of PChar =
  ('button100x30.gif', 'button100x40.gif', 'button100x50.gif',
   'button120x30.gif', 'button120x50.gif', 'button140x28.gif',
   'button88x31.gif');

Ja w zasobach umieściłem 7 plików.

Teraz najtrudniejsza część zadania - trzeba napisać procedurę, która po kolei będzie z zasobu wyciągać pliki i zapisywać je na dysku. W procedurze będzie kod odszukujący dany plik w zasobie, a następnie zapisujący jego zawartość do pliku. Procedura wygląda tak:

procedure Install(Source: String);
var
  F: File;
  I: Integer;
  Res: Integer;
begin
{
   Petla bedzie instalowala po kolei wszystkie pliki z tablicy
}
  for I := Low(Files) to High(Files) do
  begin
    Sleep(400); // czekaj 400 milisekund
    Writeln('Wypakowuje ' + Files[i]); // wyswietl informacje o wypakowanym pliku
    AssignFile(F, Source + Files[i]);
    ReWrite(F, 1); // stworz plik
  {  wyszukaj zasobu okreslonego w tablicy }
    Res := FindResource(hInstance, PChar(Files[i]), 'PHOTO');
  {  zapisz zasob do pliku }
    BlockWrite(F, LockResource(LoadResource(hInstance, Res))^, 
       SizeOfResource(hInstance, ReS));
    CloseFile(F); // zamknij plik
  end;
  Writeln('');
  { po zakonczeniu instalacji wyswietl informacje o zakonczeniu }
  Writeln('Instalacja zakończona. Naciśnij ENTER, aby zakończyć.');
  Readln; // czkeja na nacisniecie klawisza
end;

Cała procedura opiera się na wykonaniu pętli. Zawiera ona jeden parametr, który mówi o katalogu, w którym będą zainstalowane pliki. Najpierw w oknie należy wyświetlić nazwę pliku, który będzie instalowany, następnie stworzyć ten plik na dysku. Teraz trudniejsza część zadania - trzeba bowiem odszukać konkretny plik. Robi to procedura FindResource. Drugim parametrem jest nazwa odszukiwanego zasobu, a ostatni to gałąź, w którym te zasoby się znajdują. Ja plik zasobów stworzyłem przy pomocy Visual C++ i dlatego gałąź nosi nazwe PHOTO (taką sobie wybrałem).

Kolejna część procedury to zapis odszukanego zasobu to pliku. Robi to polecenie BlockWrite. W niej do pliku zostaje zapisany zasobów odszukany wcześniej przy pomocy procedury FindResource. Na końcu plik zostaje zamknięty.

Właściwie cały program mamy już napisany. Teraz tylko początek (co będzie wyświetlane po uruchomieniu programu). Ja w bloku Begin i End. umieściłem taki kod:

var
  Dir: String; // zawiera sciezke gdzie pliki maja byc zainstalowane
begin
  Writeln('');
  Writeln('   Copyright (c) 2001 by Adam Boduch   ');
  Writeln('   http://programowanie.of.pl          ');
  Writeln('');
  
  Writeln('Gdzie mam zainstalować?');
  Readln(Dir); // pobierz wpisana nazwe

  { jezeli na koncu nie ma znaku \\ to dodaj go }

  if Dir[Length(Dir)] <> '\\' then Dir := Dir + '\\';

 { stworz katalog jezeli nie istnieje lub jezeli istnieje to rozpocznij
   instalacje od razu }
  if CreateDirectory(PChar(Dir), nil) then
    Install(Dir) else Install(Dir);

end.

Tutaj następuje pobranie tekstu wpisanego przez użytkownika. Użytkownik określa katalog, w którym chce zainstalować pliki. Nastepnie jeżeli na końcu nie ma znaku \ to zostaje dodany. Później jeżeli nie ma katalogu który to użytkownik wpisał następuje stworzenie jego przy pomocy polecenia CreateDirectory. Oto cały kod programu:

program console;    

{$APPTYPE CONSOLE} // <-- aplikacja bedzie konsolowa

uses Windows;

{$R FILES.RES}

const
{  tablica plikow, ktore sa wlaczone do zasobow }
  Files : array[0..6] of PChar =
  ('button100x30.gif', 'button100x40.gif', 'button100x50.gif',
   'button120x30.gif', 'button120x50.gif', 'button140x28.gif',
   'button88x31.gif');

procedure Install(Source: String);
var
  F: File;
  I: Integer;
  Res: Integer;
begin
{
   Petla bedzie instalowala po kolei wszystkie pliki z tablicy
}
  for I := Low(Files) to High(Files) do
  begin
    Sleep(400); // czekaj 400 milisekund
    Writeln('Wypakowuje ' + Files[i]); // wyswietl informacje o wypakowanym pliku
    AssignFile(F, Source + Files[i]);
    ReWrite(F, 1); // stworz plik
  {  wyszukaj zasobu okrslonego w tablicy }
    Res := FindResource(hInstance, PChar(Files[i]), 'PHOTO');
  {  zapisz zasob do pliku }
    BlockWrite(F, LockResource(LoadResource(hInstance, Res))^, 
      SizeOfResource(hInstance, ReS));
    CloseFile(F); // zamknij plik
  end;
  Writeln('');
  { po zakonczeniu instalacji wyswietl informacje o zakonczeniu }
  Writeln('Instalacja zakończona. Naciśnij ENTER, aby zakończyć.');
  Readln; // czekaj na nacisniecie klawisza
end;

var
  Dir: String; // zawiera sciezke gdzie pliki maja byc zainstalowane
begin
  Writeln('');
  Writeln('   Copyright (c) 2001 by Adam Boduch   ');
  Writeln('   http://programowanie.of.pl          ');
  Writeln('');
  
  Writeln('Gdzie mam zainstalować?');
  Readln(Dir); // pobierz wpisana nazwe

  { jezeli na koncu nie ma znaku \\ to dodaj go }

  if Dir[Length(Dir)] <> '\\' then Dir := Dir + '\\';

 { stworz katalog jezeli nie istnieje lub jezeli istnieje to rozpocznij
   instalacje od razu }
  if CreateDirectory(PChar(Dir), nil) then
    Install(Dir) else Install(Dir);

end.

Być może temat aplikacji konsolowej nie jest aż taki trudny do opanowania, ale warto go znać.

12 komentarzy

Wierzę, że znajdę tu pomoc dla aplikacji konsolowej. Chodzi mi o zapisanie do pliku całości wyświetlanych informacji Rzecz dotyczy gry w szachy gdzie każdorazowo ( po posunięciu z mej strony) prog pisze: "Twój ruch..." po wykonaniu ruchu (wpis np:e2e4) program pisze: "mój ruch e7e5" itd. Chciałbym zapisać przebieg partii do jakiegoś pliku.

Jak ktoś chce umieć pisać w konsoli to kurs Turbo Pascala, bo to prawie to samo.

Czy jest jakaś mozliwość, żeby aplikację konsolową zrestartować ??
Chodzi mi o coś takiego, ze wszystko wraca do stanu zaraz po uruchomieniu.

" adammaj dnia 18-10-2002 11:32
Czy można rysować na ekranie w aplikacji konsolowej ?"

odp /

nam na studiach cos takiego zadali:

program pkt_D;
{$APPTYPE CONSOLE}
uses
SysUtils;

var
a,i,j:byte;
w:char;
begin
{ TODO -oUser -cConsole Main : Insert code here }
repeat
repeat
w:='c';
writeln('podaj liczbe 1-15');
readln(a);
if (a<1) or (a>15) then writeln('zly zakres') else w:='t';
until w='t';
for i:=1 to a do begin
for j:=1 to i do write(' ');
for j:=i to a do write('');
for j:=i+1 to a do write('
');
writeln;
end;
writeln('aby zakonczyc pyknij N');
readln(w);
until upcase(w)='N';
end.

http://www.pwsz.nysa.pl/~dhalikowski/przedmioty/programowanie/programowanie.htm
lista 4, pkt D

Jak wyszyścić program?! chodzi o ClrScr; ... tylko w Delphi nie dziala CRT.. wiec jak wyczyścic w delphi ? prosze o pomoc

Właśnie - to powinno być poprawione na "okno trybu tekstowego" albo coś w tym rodzaju. Poza tym jeśli to skompilujesz, to w czystym DOSie to Ci się nie uruchomi - wyświetli się komunikat "This program cannot run in DOS mode".

tak idzie semigrafiką

jest to aplikacja uruchamiana w okienku MS - DOS. Taka opcja nadaje się do pisania prostych programów, które mają być wyświetlane w okienku DOSa.

Mało co mnie nie zakrztusiło. Jak ten artykuł jescze się tutaj w tej formie utrzymał? To okienko ma tyle wspólnego z DOS-em, ze programy DOS-owe też się w takich pokazują. To jest okienko trybu tekstowego (wiersza polecenia, terminala, konsoli tekstowej jak ktoś woli), ale z oknem DOS-a to nie ma nic wspólnego (bo takie pojęcie jak "okno DOS" jest wewnętrznie sprzeczne).

eeeeee, no jasne. wszystko zrozumiałem :D

Czy można rysować na ekranie w aplikacji konsolowej ?