CRT Documentation: Reference

Using Crt

There are a number of tasks you can accomplish with the Crt unit, from utilizing the simplistic functionality afforded by a console from inside your GUI applications to enhancing the UI of your console applications with colorful interfaces and dialogues. Potential issues that may arise in porting legacy DOS applications to Win32 are also addressed below, as well as tips on how to use this unit with Delphi 2.

Enhancing GUI applications

You can use the Crt unit from both Console and GUI (graphical user interface) applications. When the unit initializes, it checks IsConsole to determine if the application is running as a console or as a GUI, and if running as a GUI, it defers initialization until AssignCrt is called. Therefore, if you want to display a console from a GUI application at run-time, you need to use the Win32 API call AllocConsole and then use AssignCrt with Reset and Rewrite to set Input and Output to the Crt routines.

uses Windows, Crt;

if (AllocConsole) then begin
  AssignCrt(Input);
  Reset(Input);
  AssignCrt(Output);
  Rewrite(Output);
end else begin
  { Handle console creation failure. }
end;

At this point you can use Write, WriteLn, Read and ReadLn to perform I/O on your new console from your GUI. You can also use the other Crt procedures and functions to modify the color attributes and screen characteristics.

Changing the color of text

To change the color of text from the default of LightGray, you need to use the TextColor procedure. For example, to change the color of output text to Red, you would issue the following in your code:

uses Crt;

TextColor(Red);
WriteLn('This will show up in red!');

Changing the background color

To change the background color from the usual default of black, you need to use the TextBackground procedure. For example, to change the text background of output text to Blue, you would issue the following in your code:

uses Crt;

TextBackground(Blue);
WriteLn('This will be showing up on a blue background!');

Reading characters from the keyboard

If you want to read characters from the keyboard, you can use KeyPressed and ReadKey. KeyPressed can be used to check for the presence of a character, and ReadKey can then be used to retrieve the character pressed.

uses Crt;

var
  C: char;
begin
  if (KeyPressed) then
    C := ReadKey;

Note that calling ReadKey when a character is not available will block until one is. This is especially important in GUI applications which must constantly be ready to update the display and respond to Window messages. An advanced technique for handling this is to use the Win32 API function MsgWaitForMultipleObjects to wait on the standard input handle, and set it to wake up on all incoming message events. You can then use Application.ProcessMessages when WAIT_OBJECT_0 + 1 (assuming the only handle you wait for is the standard input handle) is returned.

uses Forms, Windows, Crt;

var
  C: char;
begin
  case MsgWaitForMultipleObjects(1, TTextRec(Input).Handle, False, INFINITE, QS_ALLEVENTS) of
    WAIT_OBJECT_0:
      begin
        // input is available (see below for explanation)
        if (KeyPressed) then begin
          // received a key
          C := ReadKey;
        end;
      end;
    WAIT_OBJECT_0 + 1:
      begin
        // message input is available, let Delphi handle it
        Application.ProcessMessages;
      end;
  end;

This code allows your application to wait in-place for new character input without sacrificing the responsiveness of your GUI application elements.

The reason for the KeyPressed call in the WAIT_OBJECT_0 case is because when you wait on the input handle, ANY input event will trigger it (including non-keyboard related events, for example, losing and receiving the input focus). Calling KeyPressed ensures that a key is really available, and if not, clears the input queue so waiting on the input handle won't immediately fire again.

Legacy Applications

This unit also serves as a drop-in replacement for the old Turbo Pascal and Borland Pascal Crt units. While nearly all functionality has been recreated, some functionality either could not be recreated, or simply was not appropriate. This is a listing of issues you may run in to when moving an app from Turbo Pascal or Borland Pascal to Delphi and this newer Crt unit.

Many applications being ported to Delphi will require only minimal changes to compile, but there may be other issues (such as direct hardware access, or the use of interrupts) that will require more involved efforts to get working in Windows.

Delphi 2 Concerns

If using this unit with Delphi 2 you may need to manually initialize the Crt unit by using AssignCrt with the following code.

uses Crt;

AssignCrt(Input);
Reset(Input);
AssignCrt(Output);
Rewrite(Output);
CheckBreak := True;

For some reason IsConsole in Delphi 2 isn't properly initialized, and so the Crt unit may not initialize properly unless you use the code provided above.  The modification of CheckBreak is to enable the default behavior when the Crt is initialized properly on it's own.  Normally CheckBreak defaults to True, but when IsConsole is False, CheckBreak is set to False to avoid accidental termination of a GUI application via Ctrl+Break, etc.