Link to home
Start Free TrialLog in
Avatar of theraphy
theraphy

asked on

Ms-dos similar console type applications

I want to develop an application that uses a console type interface for user input like ms-dos prompt but it must run under windows not under dos so i don't want to use the conditinal define of compiler that compiles the program as a dos console type application. and i do not want to use tmemo for user input.

thanx
Avatar of Madshi
Madshi

If you look at the project options, page "Linker". There's a checkbox named "console application" or "textmode application" (I've the german version, so I can't tell you the exact name).
Check it, it should be would you need.

Regards, Madshi.
Avatar of theraphy

ASKER

Thanx madshi but this is not what i need... when you check that it generates a dos based application... i need a WINDOWS application which got a console form that behaves like ms-dos promt... for that i creted a timage and aligned it alclient and i wrote some code to form's onkeydown event for displaying the keys pressed on timage but this not give the result i need... because it has no cursor which is blinking...
Hmm. The application IS a windows application. You can call win32 functions and you can't call such a console program in dos mode...
a "console application" run only under windows 32 bits !
You can also use AllocConsole API in a GUI application to open a text mode window (still a 32bits application).

To run under DOS a console application need a 32bits DOS extender like WDOSX (freeware) !
tothpaul, that's what I said, isn't it???
Madshi is correct.  Delphi CANNOT (without some serious modifications anyway) create DOS applications.  A console app under delphi is a Win32 console, which is the same thing as what you would end up with using tothpaul's method.  Now if you want a console INTERFACE to do some kind of custom command line processing without spawning a real console, that would be something entirely different.  Is this what you are trying to do?  Please clarify.
sorry tothpaul as i said in my question i do not want that kind of solution... may be it is my fault i couldn't tell what i need but at least healthprovost understood what i am asking for... thanx healthprovost... yes i want a console interface....
What you are attempting to do is unfortunately quite involved if you were to write all the code yourself.  There is however a component on the Delphi Super Page called TConsole (and TColorConsole) which should do what you want.  The filename is consol.zip.  It is probably on other Delphi sites as well.  If a component solution is not sufficient please respond so we can explore other options.
thanx heathprovost... that is the ting i need but now i got problems using it... because it is not well documantated and i can not get any user input (like readln operation in pascal)... i've studied its source code and it is a little bit complex for me... :-( what do you think about developing a new component from tcustomedit... ?
I actually think this thread became kind of interesting. So I did some developing, and I thought this example might become usable (Though you have to hardcode most of things due to a lack of console interfaces)

The example processes user input from the keyboard, but can also be built to accept any other kind of events.

Just Make a new project and remove the unit from the project manager and the paste this to the project source:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Dialogs,
  Windows,
  Forms;

Type
  TConColor = (ccBlue,ccGreen,ccRed,ccIntens);
  TConColors = set of TConColor;

var
  Cd: TCoord;
  hOutput,hInput: hWnd;
  c: char;
  S: String[10];
  fgc,bgc: TConColors;

{$R *.RES}

   function GetNextKey(ConsoleInputHandle: hWnd): Char;
   var
     IRec: TInputRecord;
     count: Integer;
   begin
     Result:= #0;
     Repeat
       ReadConsoleInput( hInput, IRec, 1, count);
       If IRec.EventType = KEY_EVENT then
       If IRec.KeyEvent.bKeyDown then Result:= IRec.KeyEvent.AsciiChar;
     until Result<>#0;
   End;

   procedure SetColor(ConsoleOutputhandle: hWnd; fgColor,bgColor: TConColors);
   var
     C: WORD;
   begin
     C:= 0;
     If ccBlue   in fgColor then C:= C OR FOREGROUND_BLUE;
     If ccGreen  in fgColor then C:= C OR FOREGROUND_GREEN;
     If ccred    in fgColor then C:= C OR FOREGROUND_RED;
     If ccIntens in fgColor then C:= C OR FOREGROUND_INTENSITY;
     If ccBlue   in bgColor then C:= C OR BACKGROUND_BLUE;
     If ccGreen  in bgColor then C:= C OR BACKGROUND_GREEN;
     If ccred    in bgColor then C:= C OR BACKGROUND_RED;
     If ccIntens in bgColor then C:= C OR BACKGROUND_INTENSITY;
     SetConsoleTextAttribute(ConsoleOutputhandle,C);
   End;

   procedure WriteChars(code,count: Integer);
   Begin
     While count>0 do
     begin
       Write(chr(code));
       Dec(count);
     End;
   End;

begin
  fgc:= [ccRed,ccGreen,ccBlue];
  bgc:= [ccGreen];

  hOutput:= GetStdHandle(STD_OUTPUT_HANDLE);
  hInput := GetStdHandle(STD_INPUT_HANDLE );

  SetColor(hOutput,fgc,bgc);

  WriteChars(177,39); Writeln(#177);
  WriteChars(177,40); Writeln(#0);
  WriteChars(177,9);

  Exclude(bgc,ccGreen);
  SetColor(hOutput,fgc,bgc);
  Write(' Username:');
  WriteChars(32,12);

  Include(bgc,ccGreen);
  SetColor(hOutput,fgc,bgc);
  WriteChars(177,9);  Writeln(#0);
  WriteChars(177,40); Writeln(#0);
  WriteChars(177,40); Writeln(#0);

  Exclude(bgc,ccGreen);
  SetColor(hOutput,fgc,bgc);
  SetColor(hOutput,fgc,bgc);
  Write(#32);

  Include(bgc,ccGreen);
  SetColor(hOutput,fgc,bgc);
  WriteChars(32,40);
  Exclude(bgc,ccGreen);
  SetColor(hOutput,fgc,bgc);

  Cd.X:= 20;
  Cd.Y:= 2;

  SetConsoleCursorPosition(hOutput,Cd);

  Repeat
    c:= GetNextKey(hInput);
    If (c=#8) AND (S<>'') then
    Begin
      Delete(S,Length(S),1);
      write(#8#0#8);
    End else
    If (ord(c)>31) AND (Length(S)<10) then
    Begin
      S:= S + C;
      write(c);
    End;
  Until c = #13; //User pressed return

  ShowMessage('Username: '+S);
end.

Regards,
Williams
Ok, I really don't know what you want when you say you don't want to generate a console application, but anyhow I find the example quite funny

sorry another thing, just write:

uses
  Windows;

instead of all the other stuff in the uses clause, and your compiled program will only take up 17 Kb. :-)

Cheers,
Williams
I'll be da...

Forgot, that you cannot use the Showmessage then :-) ..replace it with:

  Cd.X:= 0;
  Cd.Y:= 7;
  SetConsoleCursorPosition(hOutput,Cd);
  WriteLn('Username: '+S);
  Write('<Press a key to exit>');
  c:= GetNextKey(hInput);
Okay ! you can also use WINCRT Unit !

Look at my CrtSock unit, Pascal TextFiles can be used to read from/write to anything !

Regards
Paul TOTH
http://www.multimania.com/tothpaul

tothpaul where can ifind wincrt unit? and some information about it? i looked at delphi help but tere's nothimg about it and added it uses clause and delphi generated an error because of not finding it...
tothpaul i've found and used wincrt unit it again does not provide what i need.. as heatprovost said i need a console type interface...
have you testet my example ? ..is it something like this you are looking for ?

Then I guess you will find it a bit difficult to find. You can ask yourself how many are interested in coding a complete console Interface with windowed controls under windows 95/98/NT? ..But anyway, it can be done like the way I described OR by using Borland Turbo PASCAL, but that's 16bit of course :-(

Cheers,
Williams
thanx williams2 but this is not i need.

what i am exactly trying to do is developing an ai based programming language and for this reason the language development environment needs a console type interface which prompts program outputs and gets user commands. just like the one in amzi prolog listener.
Then please tell me what's wrong with my first suggestion? I still think it is what you need. IT IS NO DOS PROGRAM, BUT A REAL WIN32 BIT CONSOLE PROGRAM!

Regards, Madshi.
ok madshi it is awin32 bit console program and IT IS A PROGRAM... i need a component just like a tmemo. let me tell you my program interface. first of all it is not a mdi application. it got three sections one of them is editor section, one of them is messages section and the last one is console section. all of them are displayed on tpanel and have splitters between them. so when the user enters the console section the user can give some specific commands to compile program into memory or etc. it looks like this :

?- consult(myprogram).
yes.

the "?-" is command line prompt... and "yes" is the respond of the program..


with your suggest i can only develop a console type PROGRAM.... but i need a console type interface to use with other visual components...

thanx anyway...

Ahhh - now I understand it...  :-)

If you don't find a component that is good enough, you could do it yourself. I would suggest using a TRichEdit (because there you can easily use different colors for input and output). Unfortunately I have not the time to implement a ready-to-use component for you, but this should help you (I hope):

var OldEditWndProc : integer;
    edit           : TRichEdit;
    inputText      : string;

function EditHookProc(hwnd, msg,wparam,lparam: integer) : integer; stdcall;
begin
  result:=0;
  case msg of
    WM_SETTEXT, WM_GETTEXT, WM_GETTEXTLENGTH, WM_COPYDATA, WM_CUT, WM_COPY, WM_PASTE, WM_CLEAR, WM_DDE_FIRST..WM_DDE_LAST : exit;
    WM_KEYDOWN, WM_KEYUP : exit;
    WM_CHAR              : if wParam=VK_BACK then begin
                             exit;
                           end else if wParam=VK_RETURN then begin
                             // here you can fire an ReadLn event with "inputText"...
                             edit.selAttributes.color:=clBlack;
                             CallWindowProc(pointer(OldEditWndProc),hwnd,msg,182,0);
                             result:=CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,lparam);
                             edit.selAttributes.color:=clNavy;
                             inputText:='';
                             exit;
                           end else if wParam=VK_TAB then begin
                             beep;
                             exit;
                           end else if wParam=VK_SPACE then begin
                             inputText:=inputText+#32;
                             edit.selAttributes.color:=clBlack;
                             CallWindowProc(pointer(OldEditWndProc),hwnd,msg,183,0);
                             edit.selAttributes.color:=clNavy;
                             exit;
                           end else if (wParam<256) and (chr(wParam) in [#9,#13,#32..#126,#128,#145,#167,#176,#178..#181,#192..#255]) then begin
                             inputText:=inputText+#32;
                             exit;
                           end else exit;
    WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP,
    WM_RBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MBUTTONDBLCLK, WM_MOUSEWHEEL : exit;
  end;
  result:=CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,lparam);
end;

procedure HookRichEdit;
begin
  with edit.font do begin size:=12; name:='Courier New'; color:=clNavy end;
  OldEditWndProc:=SetWindowLong(edit.handle,GWL_WNDPROC,integer(@EditHookProc));
end;

Just make a new project, add a RichEdit component on it, put it into the edit variable ("edit:=form1.richEdit1"), call HookRichEdit and run it.

Surely you'll have to make some (perhaps a lot?) of changes, but I hope you understand how it works...

Regards, Madshi.

P.S: I copied it (and changed it a little bit) from one of my sources, so it does some strange things. Don't get confused because of that...   :-)
YES... THAT'S IT THANX MADSHI :-))))

now let me give you 100 points...

regards...
by the way madshi this is the modified version of your solution as you see i only did a few minor changes...
var
  OldEditWndProc : integer;
  edit           : TRichEdit;
  inputText      : string;

function EditHookProc(hwnd, msg,wparam,lparam: integer) : integer; stdcall;
begin
  result := 0;
  case msg of
    WM_SETTEXT, WM_GETTEXT,WM_GETTEXTLENGTH, WM_COPYDATA, WM_CUT,
    WM_COPY, WM_PASTE, WM_CLEAR,
    WM_DDE_FIRST..WM_DDE_LAST : exit;

    WM_KEYDOWN : if wparam in [vk_left, vk_right, vk_down, vk_up, vk_back] then
                 begin
                   result := CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,lparam);
                   exit;
                 end else exit;

    WM_KEYUP : exit;

    WM_CHAR : if wParam=VK_RETURN then begin
                result:=CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,lparam);
                if (inputtext <> '') and (inputtext[length(inputtext)] = '.') then
                begin
                  // after this point process the command and
                  // display the answer, again scroll down one line
                  // CallWindowProc(pointer(OldEditWndProc),hwnd,msg,13,0);
                  // display the command line prompt
                  CallWindowProc(pointer(OldEditWndProc),hwnd,msg,63,0);
                  CallWindowProc(pointer(OldEditWndProc),hwnd,msg,150,0);
                  CallWindowProc(pointer(OldEditWndProc),hwnd,msg,32,0);
                  // and then initialize input text :-> inputText:='';
                end;
                exit;
              end else if wParam=VK_TAB then begin
                beep;
                exit;
             end else if (wParam<256) and (chr(wParam) in [#32..#126,
             #128,#145,#167,#176,#178..#181,#192..#255]) then begin
                CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,0);
                inputText:=inputText + chr(wparam);
                exit;
              end else exit;

    WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK,
    WM_RBUTTONDOWN, WM_RBUTTONUP, WM_RBUTTONDBLCLK, WM_MBUTTONDOWN,
    WM_MBUTTONUP, WM_MBUTTONDBLCLK, WM_MOUSEWHEEL : exit;
  end;
  result:=CallWindowProc(pointer(OldEditWndProc),hwnd,msg,wparam,lparam);
end;

procedure HookRichEdit;
begin
  with edit.font do begin
    size:=10;
    name:='Courier New';
    color:=clNavy
  end;
  OldEditWndProc:=SetWindowLong(edit.handle,GWL_WNDPROC,integer(@EditHookProc));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  edit := richedit1;
  // display the commnd line prompt
  sendmessage(richedit1.handle, wm_char, 63, 0);
  sendmessage(richedit1.handle, wm_char, 150, 0);
  sendmessage(richedit1.handle, wm_char, 32, 0);
  hookrichedit;
end;

thanx again.. :-)
ASKER CERTIFIED SOLUTION
Avatar of Madshi
Madshi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial