unit wDebug0;

{ Feel free to use this unit as you want.
  First developped by Bernard Gisin
  This unit can be usefull while developping, to write informations into a window,
  called the debugging window.
  To use it, add this unit in the uses, typically :
  uses  Strings,Windows,wDebug0;

  Then each time you want to write information in the debugging window, call
  DBW0(wNumber, string);
  If the debugging window is not open, it will open automatically.
  string is the information you want to be written.

  functions like  IntToStr,  ...  are usefull to convert numbers or pointers into
  strings. for example :
  strS:='first number =' + ITS(number) + '  pointer value =' + PTS(ptr);
  DBW0(8,strS);
  A line break (=return) is added automatically at the end of the line.

  The  wNumber  parameter allow to avoid writing the string.
  If (wNumber and gllMask) <> 0 then DBW0(wNumber, strS); will do nothing.
  gllMask can be changed through the menu of the debugging window, while
  the program is running.
  Thus you can select during debugging which information you want to hide temporarly.
  If you don't want to use it, put  0  as a value for wNumber.

  If you call  DBW0(0,'');  the debugging window will be opened, but nothing
  will be written in it.

  When the debugging window is closed,
  the position, size and value of gllMask are stored into the file  DebugWin.prm
  in the same directory as the  .exe file. They are re-used the next time the
  debugging window is opened.

  See GetSystemInfo(lpSystemInfo:LPSYSTEM_INFO);
  to get information about the system.
  But the resources available are not given here.
-----------------------------------------------------}

INTERFACE
//"""""""

uses windows;

procedure DBSavePositionAndSize;
//==============================
{ Save in a text file the position and size of the debugging window,
  in order to restore the same position and size, at the next
  creation of the debugging window.
  Noramlly there is no reason to call it, since it is called
  automatically when the debugging window is closed, and
  when the application is terminated.
  ------------------------------------------------------------}

function IntToStr(nn:longint; nFmt:integer):ShortString;
// Convert int32 to string

function WordToStr(ww:Cardinal; nFmt:integer):Shortstring;
//========================================================
// Convert word32 to string

function FloatToStr(vv:Double; nFmt1,nFmt2:integer):ShortString;
// Convert double to string

function PtrToStr(pp:pointer; nFmt:integer):ShortString;
// Convert pointer to string

// convertion with standard values
function ITS(nn:longint):ShortString;
function ITS5(nn:longint):ShortString;
function WTS(ww:Cardinal):ShortString;
function WTS5(ww:Cardinal):ShortString;
function FTS(vv:Double):ShortString;
function PTS(pp:pointer):ShortString;

function DBMsgToStr(wMsg:word):Shortstring;
//=========================================
{ Converts a message number into the corresponding message string
  used in windows.
  -------------------------------------------------------}

function DBNotifToStr(lNotif:longint):Shortstring;
//================================================
{ Converts a notification message number into the corresponding
  notification message string, used in windows.
  Only for some notifications. The EN_notifications.
  -------------------------------------------------------}

procedure DBWaitSec(nSec:integer);
// Waits nSec before continuing

procedure DBShowMemoryInfo(wMask:word);
//=====================================
// Gives some informations about memory status
// Writes the data in the debug window

procedure DBW0(lMask:longint; strS:Shortstring);
//==============================================
{ procedure used to write text in a debugging window
  If lMask = 0 => everything is written
------------------------------------------------------}

procedure DBW(lMask:longint; strS:Shortstring);
// Same as DBW0

const  gglfDBInitDone   : boolean = FALSE;
// has the debugging window been created ?
// In very special cases, it might be a problem to acces to DBW0(..)
// when the debugging window is not opened, i.e. when gglfDBInitDone=FALSE

  gglstrDebugPathName : ShortString = '';
  // If this is set to a pathname, it is where the debug parameters
  // are being loaded and saved.

IMPLEMENTATION
//""""""""""""

Uses Strings;

const
  glcteAppName = 'DebWin';

  // name of the file where parameters concerning the debugging window are stored
  glcteDebugFilename = 'DebugWin.prm';

const
  glfRegistered : boolean = FALSE; // has the 'DebWin' window been registered ?
                                   // it has to be registered only once.
  glfPrmLoaded  : boolean = FALSE; // has the parameters been ridden ?
//  gglfDBInitDone   : boolean = FALSE; // has the debugging window been created ?
                                     // in interface part.

  // while initialisation is beeing done, cannot enter again in the
  // DBW0 procedure.
  glfWhileInit : boolean = FALSE;

type
  str200      = string[200];

var
  glhWindow   : HWnd; // handle on the debugging window
  glhEdit     : HWND;
  gllMask     // bits to be masked when wrinting in the debugging window
              : longint;
  glnXPos,  glnYPos,  // X and Y position of the debugging window
  glnWidth, glnHeight // size of the debugging window
              : integer ;
  glstrFileName // name of the file where the texte is being saved
              : str200;
  glfShowMaskNumber // indicate if after the text, the mask number is displayed.
              : boolean;

var nNotUsed : integer; // only to avoid an error message while compliling in DevPascal 1.9

function FileDir(strPath:str200):str200;
//======================================
{ Returns the directory part of the full Path name,
  with a  '\'  at the end.
  ----------------------------------------------------------------}
var
  nLen,       // length of strPath
  nLast,      // position of the last  '\'
  nn          : integer;
  strDir      // directory part of strPath
              : str200;
begin
nLen:=length(strPath);
nLast:=0;

// search the last occurence of '\' in the file full path name
for nn:=1 to nLen do if (strPath[nn] = '\') then nLast:=nn;

// copy the path part of the strPath
strDir:='';
for nn:=1 to nLast do strDir:=strDir + strPath[nn];

strDir:=strDir + '\';
FileDir:=strDir;
end;  // FileDir

procedure DBSavePositionAndSize;
//==============================
{ Save in a text file the position and size of the debugging window,
  in order to restore the same position and size, at the next
  creation of the debugging window.
  ------------------------------------------------------------}
var
  fOut        : text;
  nErr        : integer;
  strDir,     // directory of the .exe file
  strS        : str200;

begin
if (gglstrDebugPathName <> '') then strS:=gglstrDebugPathName
else begin
   strS:=ParamStr(0); // directory and name of the .exe file
   strDir:= FileDir(strS);
   strS:=strDir + glcteDebugFilename;
   end;

{$i-}
assign(fOut, strS);
rewrite(fOut);

nErr:=IOResult;
if (nErr <> 0) then exit;

writeln(fOut, '...Signature DebugWindow');
writeln(fOut, 101); // Version number
writeln(fOut, glnXPos:6);
writeln(fOut, glnYPos:6);
writeln(fOut, glnWidth:6);
writeln(fOut, glnHeight:6);

writeln(fOut, gllMask:12);

writeln(fOut, ord(glfShowMaskNumber):6);  // 101

Close(fOut);
nErr:=IOResult;
{$i+}
end;  // DBSavePositionAndSize

procedure LoadPositionAndSize;
//============================
{ Load from a file the position and size of the debugging window to be set }
var
  fIn         : text;
  nVersion,
  nErr        : integer;
  strDir,     // directory of the .exe file
  strS        : str200;

begin
// set the default position and site of the debugging window
glnXPos   :=600;
glnYPos   := 10;
glnWidth  :=200;
glnHeight :=550;
gllMask   :=0;
glfShowMaskNumber := TRUE;

{$i-}
if (gglstrDebugPathName <> '') then strS:=gglstrDebugPathName
else begin
   strS:=ParamStr(0); // directory and name of the .exe file
   strDir:= FileDir(strS);
   strS:=strDir + glcteDebugFilename;
   end;

assign(fIn, strS);
FileMode := 0;  // Set file access to read only
reset(fIn);
FileMode := 2;  // Set file access to read/write

nErr:=IOResult;
if (nErr <> 0) then exit; // file doesn't exist

readln(fIn, strS);  { signature }
readln(fIn, nVersion);

readln(fIn, glnXPos);
readln(fIn, glnYPos);
readln(fIn, glnWidth);
readln(fIn, glnHeight);

readln(fIn, gllMask);

if (nVersion >= 101) then readln(fIn, byte(glfShowMaskNumber));

Close(fIn);
nErr:=IOResult;
{$i+}

glfPrmLoaded:=TRUE;
end;  // LoadPositionAndSize

// ***********************************************************
// Saving and loading a new text in the debugging window
// ***********************************************************

function SelectFile(var strFName:str200; Open:Boolean): Boolean;
//==============================================================
const
  Filter      : PChar = 'Text files (*.txt)'#0'*.txt'#0 +
                        'All files (*.*)'#0'*.*'#0#0;
  Ext         : PChar = 'txt';
var
  NameRec     : OpenFileName;

begin
FillChar(NameRec,SizeOf(NameRec),0);
strFName := #0;
with NameRec do begin
   lStructSize := SizeOf(NameRec);
   hWndOwner   := glhWindow;
   lpStrFilter := Filter;
   LpStrFile   := @strFName[1];
   nMaxFile    := Max_Path;
   Flags       := OFN_Explorer Or OFN_HideReadOnly;
   if Open then begin
      Flags := Flags Or OFN_FileMustExist;
      end;

   lpStrDefExt := Ext;
   end; // with NameRec

if Open then SelectFile := GetOpenFileName(@NameRec)
else         SelectFile := GetSaveFileName(@NameRec);

// convert the lpz string into a pascal string
strFName[0]:=char(strlen(@strFName[1]));
end;  // SelectFile

procedure SaveText;
//=================
var
  lLen        : Longint;
  pCh         : PChar;
  fOut        : File;
  strFName    : str200;

begin
if SelectFile(strFName,False) then begin
   Assign(fOut,strFName);
   Rewrite(fOut,1);
   lLen := GetWindowTextLength(glhEdit);
   GetMem(pCh,lLen+1);
   pCh[lLen] := #0;

   if (lLen > 0) then begin
      GetWindowText(glhEdit, pCh, lLen+1);
      BlockWrite(fOut, pCh^, lLen);
      end;

   Close(fOut);

   FreeMem(pCh, lLen+1);
   SendMessage(glhEdit, EM_SetModify, 0, 0);
   end;  // if
end;  // SaveText

procedure AskSave;
//================
const
  BoxType = MB_IconQuestion Or MB_YesNo;

begin
if SendMessage(glhEdit,EM_GetModify,0,0)<>0 then begin
   if MessageBox(glhWindow,'Save text?','Edited',BoxType)=IdYes then begin
      SaveText;
      end;
   end;
end;  // AskSave

procedure LoadText;
//=================
var
  fIn         : File;
  lLen        : LongInt;
  pCh         : PChar;
begin
AskSave;
if SelectFile(glstrFileName, TRUE) then begin
   Assign(fIn, glstrFileName);
   Reset(fIn,1);
   lLen := FileSize(fIn);
   GetMem(pCh, lLen+1);
   pCh[lLen] := #0;
   if (lLen > 0) then BlockRead(fIn, pCh^, lLen);
   Close(fIn);
   SetWindowText(glhEdit, pCh);
   SendMessage(glhEdit, EM_SetModify, 0, 0);
   FreeMem(pCh, lLen+1);
   end;
end;  // LoadText

procedure NewText;
//================
const
  Empty       : PChar = '';

begin
AskSave;
glstrFileName := 'Unsaved';
SendMessage(glhEdit, WM_SetText, 1, LongInt(Empty));
SendMessage(glhEdit, EM_SetModify, 0, 0);
end;  // NewText

// ************************************************
// WindowProc, Window creation and Edit creation
// ************************************************

function WindowProc(hWindow:HWND;AMessage:UINT;wPar:WPARAM;lPar:LPARAM):LRESULT; stdcall; export;
//================================================================================================
var
  rWndRect    : rect;
  lNrMenu     : Longint;
  lNotiCode   : LongInt;
  hMenuWin        : hMenu;
  wCheck      : word;
  lPow2       : longint; // 2 power the mask to be toggled
  nCount      : integer; // to compute lPow2
  strS        : string[50];

begin
WindowProc := 0;
Case AMessage Of
//   WM_Close:begin end;
   WM_Destroy:begin  // last message before destruction
//     AskSave;
      DBSavePositionAndSize;
      gglfDBInitDone:=FALSE;
      end;
   WM_SetFocus:begin
      SetFocus(glhEdit);
      end;
   WM_EraseBkgnd:begin
      Exit(1);
      end;
   WM_Size:begin
      GetClientRect(hWindow,@rWndRect);
      MoveWindow (glhEdit,0,0,rWndRect.Right,rWndRect.Bottom,False);

     // gets the actual position and size of the debugging window
     GetWindowRect(hWindow, rWndRect);
     glnXPos   :=rWndRect.left;
     glnYPos   :=rWndRect.top;
     glnWidth  :=rWndRect.right  - rWndRect.left;
     glnHeight :=rWndRect.bottom - rWndRect.top;
     end;
   WM_Move:begin
      GetClientRect(hWindow,@rWndRect);
      MoveWindow (glhEdit,0,0,rWndRect.Right,rWndRect.Bottom,False);

     // gets the actual position and size of the debugging window
     GetWindowRect(hWindow, rWndRect);
     glnXPos   :=rWndRect.left;
     glnYPos   :=rWndRect.top;
     glnWidth  :=rWndRect.right  - rWndRect.left;
     glnHeight :=rWndRect.bottom - rWndRect.top;
     end;
   WM_Command:begin
      lNotiCode := HiWord(WPar);
      Case lNotiCode of
         EN_ERRSPACE : begin
            // Espace missign in the edit box
            // to delete, must be in read-write mode
            SendMessage(glhEdit, EM_SetReadOnly, 0 {0=Read-Write.}, 0);

            // select part of the text, delete it and goes to the end
            SendMessage(glhEdit, em_SetSel, 0, 2000);
            SendMessage(glhEdit, wm_Clear, 0, 0);
            SendMessage(glhEdit, em_SetSel, -1, -1);
            strS:='Text missing...' + #13 + #10 + #0;
            SendMessage(glhEdit, em_ReplaceSel, 0, longint(@strS[1]));
            end;

         en_Change:begin //Editor has changed
         // do nothing
         end; // en_Change
      else begin //Menu item  (else of case lNotiCode of)
         lNrMenu := LoWord(WPar);
         Case lNrMenu Of
            101 : NewText;
            102 : LoadText;
            103 : SaveText;
            109 : PostMessage(hWindow,WM_Close,0,0);
            // a test
            111 : SendMessage(glhEdit, em_SetSel, 100000000, 100000000); // position the caret at the end of the text
            201 : SendMessage(glhEdit,WM_Undo,0,0);
            202 : SendMessage(glhEdit,WM_Cut,0,0);
            203 : SendMessage(glhEdit,WM_Copy,0,0);
            204 : SendMessage(glhEdit,WM_Paste,0,0);

            299 : begin // Toggle Show mask number
                  hMenuWin:=GetMenu(hWindow);
                  if (hMenuWin <> 0) then begin
                     glfShowMaskNumber:=not glfShowMaskNumber;
                     if glfShowMaskNumber then wCheck:=MF_CHECKED
                     else                      wCheck:=MF_UNCHECKED;

                     CheckMenuItem(hMenuWin, lNrMenu, MF_BYCOMMAND or wCheck);
                     end;
                  end;
            300..330 : begin // Toggle Show mask number
                  lPow2:=1;
                  nCount:=lNrMenu - 300;
                  while (nCount >= 1) do begin
                     lPow2:=2*lPow2;
                     dec(nCount);
                     end;

                  // lPow2 = 2 power  (lNrMenu - 300)

                  hMenuWin:=GetMenu(hWindow);
                  if (hMenuWin <> 0) then begin
                     if ((gllMask and lPow2) = 0) then begin
                        gllMask:=gllMask + lPow2;
                        wCheck:=MF_CHECKED;
                        end
                     else begin
                        gllMask:=gllMask - lPow2;
                        wCheck:=MF_UNCHECKED;
                        end;

                     CheckMenuItem(hMenuWin, lNrMenu, MF_BYCOMMAND or wCheck);
                     end;
                  end;
            401 : MessageBox( hWindow,'Help','Not implemented',
                              MB_OK Or MB_IconInformation);
            end; // Case lNrMenu Of
         end; // else of case lNotiCode of
         end; // Case lNotiCode of
      end; // WM_Command
{   WM_CtlColorEdit:begin
      SetTextColor(WPar,TheColor);
      Exit(GetSysColorBrush(COLOR_WINDOW));
      end;
}    end; // Case AMessage Of

WindowProc := DefWindowProc(hWindow, AMessage, wPar, lPar);
end;  // WindowProc

procedure WinCreate;
//==================
var
  hMenuWin        : hMenu;
  SubMenu     : hMenu;
  lPow2       : longint; // 2 power the mask to be toggled
  nCount      : integer; // to compute lPow2
  wCheck      : word;
  hWinActive  : HWND;  // handle on the active window
  hWinFocus   : HWND;  // handle on the window having the focus

begin
// get the handle of the active window,
// to set it active again after the creation of the debugging window.
hWinActive:=GetActiveWindow;
hWinFocus :=GetFocus;

glhWindow := CreateWindow (glcteAppName,'Debugging Window',ws_OverlappedWindow,
                           glnXPos,glnYPos,glnWidth,glnHeight
                           ,0,0,MainInstance,NIL);
if (glhWindow <> 0) then begin
   hMenuWin := CreateMenu;
   SubMenu := CreateMenu;
   AppendMenu(Submenu,MF_STRING,101,'&New...');
   AppendMenu(Submenu,MF_STRING,102,'&Open...');
   AppendMenu(Submenu,MF_STRING,103,'&Save...');
//   AppendMenu(Submenu,MF_STRING,111,'Test &1...');
//   AppendMenu(Submenu,MF_STRING,112,'Test &2...');
   AppendMenu(Submenu,MF_SEPARATOR,0,NIL);
   AppendMenu(SubMenu,MF_String,109,'E&xit');
   AppendMenu(hMenuWin,MF_POPUP,SubMenu,'&File');

   SubMenu := CreateMenu;
   AppendMenu(SubMenu,MF_String,201,'&Undo'#8'Ctrl+Z');
   AppendMenu(Submenu,MF_SEPARATOR,0,NIL);
   AppendMenu(SubMenu,MF_String,202,'&Cut'#8'Ctrl+X');
   AppendMenu(SubMenu,MF_String,203,'&Copy'#8'Ctrl+C');
   AppendMenu(SubMenu,MF_STRING,204,'&Paste'#8'Ctrl+V');
   AppendMenu(hMenuWin,MF_POPUP,SubMenu,'&Edit');

   SubMenu := CreateMenu;
   AppendMenu(SubMenu,MF_String,299,'Toggle &Show mask number');
   AppendMenu(Submenu,MF_SEPARATOR,0,NIL);
   AppendMenu(SubMenu,MF_String,300,'&0 Toggle mask 1');
   AppendMenu(SubMenu,MF_String,301,'&1 Toggle mask 2');
   AppendMenu(SubMenu,MF_String,302,'&2 Toggle mask 4');
   AppendMenu(SubMenu,MF_String,303,'&3 Toggle mask 8');
   AppendMenu(SubMenu,MF_String,304,'&4 Toggle mask 16');
   AppendMenu(SubMenu,MF_String,305,'&5 Toggle mask 32');
   AppendMenu(SubMenu,MF_String,306,'&6 Toggle mask 64');
   AppendMenu(SubMenu,MF_String,307,'&7 Toggle mask 128');
   AppendMenu(SubMenu,MF_String,308,'&8 Toggle mask 256');
   AppendMenu(SubMenu,MF_String,309,'&9 Toggle mask 512');
   AppendMenu(SubMenu,MF_String,310,'&A Toggle mask 1024');
   AppendMenu(SubMenu,MF_String,311,'&B Toggle mask 2048');
   AppendMenu(SubMenu,MF_String,312,'&C Toggle mask 4096');
   AppendMenu(SubMenu,MF_String,313,'&D Toggle mask 8192');
   AppendMenu(SubMenu,MF_String,314,'&E Toggle mask 16384');
   AppendMenu(SubMenu,MF_String,315,'&F Toggle mask 32768');
   AppendMenu(SubMenu,MF_String,316,'&G Toggle mask 65536');
   AppendMenu(SubMenu,MF_String,317,'&H Toggle mask 131072');
   AppendMenu(SubMenu,MF_String,318,'&J Toggle mask 262144');
   AppendMenu(hMenuWin,MF_POPUP,SubMenu,'&Masks');

//   AppendMenu(hMenuWin,MF_STRING,401,'&Help');
   SetMenu(glhWindow, hMenuWin);
   ShowWindow(glhWindow, SW_SHOWNORMAL);

   // Sets the active window, the active one before creation of this window
   SetActiveWindow(hWinActive);

   // Give back the focus to the window which had it.
   SetFocus(hWinFocus);

   // Sets the check marks in the Masks menu
   if glfShowMaskNumber then wCheck:=MF_CHECKED
   else                      wCheck:=MF_UNCHECKED;
   CheckMenuItem(hMenuWin, 299, MF_BYCOMMAND or wCheck);

   // check mark of each Toggle mask
   lPow2:=1;
   for nCount:=0 to 18 do begin
      // lPow2 = 2 power nCount
      if ((gllMask and lPow2) <> 0) then wCheck:=MF_CHECKED
      else                               wCheck:=MF_UNCHECKED;
      CheckMenuItem(hMenuWin, 300 + nCount, MF_BYCOMMAND or wCheck);

      lPow2:=2*lPow2;
      end; // for nCount
   end; // if (glhWindow <> 0) then begin
end;  // WinCreate

function WinRegister: Boolean;
//============================
var
  WindowClass : WndClass;

begin
with WindowClass do begin
   Style         := cs_hRedraw Or cs_vRedraw;
   lpfnWndProc   := WndProc(@WindowProc);
   cbClsExtra    := 0;
   cbWndExtra    := 0;
   hInstance     := system.MainInstance;
   hIcon         := LoadIcon (0,idi_Application);
   hCursor       := LoadCursor (0,idc_Arrow);
   hbrBackground := GetStockObject(GRAY_BRUSH);
   lpszMenuName  := NIL;
   lpszClassName := glcteAppName;
   end;

WinRegister := RegisterClass (WindowClass)<>0;
end;  // WinRegister

function EditCreate: HWnd;
//========================
const
  CS_Start    = WS_Child or WS_HScroll or WS_VScroll or ES_MultiLine or ES_Left;
  CS_Ex       = WS_EX_ClientEdge;
  EdiTText    : PChar = '';

var
  R     : TRect;
  TheLogFont            : TLogFont;
//  TheColor              : DWORD;
  TheFont               : HFont;

begin
GetClientRect(glhWindow,@R);
glhEdit:=CreateWindowEx( CS_Ex,'EDIT',EditText,CS_Start,0,0,
                         R.Right-R.Left,R.Bottom-R.Top,glhWindow,0,
                         MainInstance,NIL);
if (glhEdit <> 0) then begin
   //Set Courier new as default font
   with TheLogFont do begin
      lfHeight         := 0;                // Default logical height of font
      lfWidth          := 0;                // Default logical average character width
      lfEscapement     := 0;                // angle of escapement
      lfOrientation    := 0;                // base-line orientation angle
      lfWeight         := FW_NORMAL;        // font weight
      lfItalic         := 0;                // italic attribute flag
      lfUnderline      := 0;                // underline attribute flag
      lfStrikeOut      := 0;                // strikeout attribute flag
      lfCharSet        := DEFAULT_CHARSET;  // character set identifier
      lfOutPrecision   := OUT_DEFAULT_PRECIS;  // output precision
      lfClipPrecision  := CLIP_DEFAULT_PRECIS; // clipping precision
      lfQuality        := DEFAULT_QUALITY;     // output quality
      lfPitchAndFamily := DEFAULT_PITCH;    // pitch and family
      Strcopy(lfFaceName,'Courier New');    // pointer to typeface name string
      end; // with
//      TheColor := GetSysColor(COLOR_WINDOWTEXT);
      TheFont  := CreateFontIndirect(@TheLogFont);
      SendMessage(glhEdit,WM_SETFONT,TheFont,1);
      ShowWindow(glhEdit,SW_Show);
      UpdateWindow(glhEdit);
   end; // if

EditCreate := glhEdit;

// Sets the limit text size contained in the rich text control.
// by default it is about 30000 bytes.
// Cannot be set much higher
SendMessage(glhEdit, EM_SETLIMITTEXT, 0, 32760);
end;  // EditCreate

function IntToStr(nn:longint; nFmt:integer):Shortstring;
//======================================================
// Convert int32 to string
var  strS : ShortString;
begin
Str(nn:nFmt, strS);
IntToStr:=strS;
end;  // IntToStr

function WordToStr(ww:Cardinal; nFmt:integer):Shortstring;
//========================================================
// Convert word32 to string
var  strS : ShortString;
begin
Str(ww:nFmt, strS);
WordToStr:=strS;
end;  // WordToStr

function FloatToStr(vv:Double; nFmt1,nFmt2:integer):ShortString;
//==============================================================
// Convert double to string
var  strS : string;
begin
Str(vv:nFmt1:nFmt2, strS);
FloatToStr:=strS;
end;  { - IntToFloat - }

function PtrToStr(pp:pointer; nFmt:integer):ShortString;
//======================================================
// Convert pointer to string
var  strS : string;
begin
Str(Longint(pp):nFmt, strS);
PtrToStr:=strS;
end;  // PtrToStr

// convertion with standard values
// *******************************

function ITS(nn:longint):ShortString;
//===================================
begin
ITS:=' ' + IntToStr(nn,9);
end;

function ITS5(nn:longint):ShortString;
//====================================
begin
ITS5:=' ' + IntToStr(nn,5);
end;

function WTS(ww:Cardinal):ShortString;
//====================================
begin
WTS:=' ' + WordToStr(ww,9);
end;

function WTS5(ww:Cardinal):ShortString;
//=====================================
begin
WTS5:=' ' + WordToStr(ww,5);
end;

function FTS(vv:Double):ShortString;
//==================================
begin
FTS:=' ' + FloatToStr(vv,12,5);
end;

function PTS(pp:pointer):ShortString;
//===================================
begin
PTS:=' ' + PtrToStr(pp,12);
end;

function DBMsgToStr(wMsg:word):ShortString;
//=========================================
{ Converts a message number into the corresponding message string
  used in windows.
  -------------------------------------------------------}
var strS : string[50];
begin
   case wMsg of
       0 : strS:= 'WM_NULL';
       1 : strS:= 'WM_CREATE';
       2 : strS:= 'WM_DESTROY';
       3 : strS:= 'WM_MOVE';
       5 : strS:= 'WM_SIZE';
       6 : strS:= 'WM_ACTIVATE';
       7 : strS:= 'WM_SETFOCUS';
       8 : strS:= 'WM_KILLFOCUS';
      10 : strS:= 'WM_ENABLE';
      11 : strS:= 'WM_SETREDRAW';
      12 : strS:= 'WM_SETTEXT';
      13 : strS:= 'WM_GETTEXT';
      14 : strS:= 'WM_GETTEXTLENGTH';
      15 : strS:= 'WM_PAINT';
      16 : strS:= 'WM_CLOSE';
      17 : strS:= 'WM_QUERYENDSESSION';
      18 : strS:= 'WM_QUIT';
      19 : strS:= 'WM_QUERYOPEN';
      20 : strS:= 'WM_ERASEBKGND';
      21 : strS:= 'WM_SYSCOLORCHANGE';
      22 : strS:= 'WM_ENDSESSION';
      24 : strS:= 'WM_SHOWWINDOW';
      26 : strS:= 'WM_WININICHANGE or WM_SETTINGCHANGE';
      27 : strS:= 'WM_DEVMODECHANGE';
      28 : strS:= 'WM_ACTIVATEAPP';
      29 : strS:= 'WM_FONTCHANGE';
      30 : strS:= 'WM_TIMECHANGE';
      31 : strS:= 'WM_CANCELMODE';
      32 : strS:= 'WM_SETCURSOR';
      33 : strS:= 'WM_MOUSEACTIVATE';
      34 : strS:= 'WM_CHILDACTIVATE';
      35 : strS:= 'WM_QUEUESYNC';
      36 : strS:= 'WM_GETMINMAXINFO';
      38 : strS:= 'WM_PAINTICON';
      39 : strS:= 'WM_ICONERASEBKGND';
      40 : strS:= 'WM_NEXTDLGCTL';
      42 : strS:= 'WM_SPOOLERSTATUS';
      43 : strS:= 'WM_DRAWITEM';
      44 : strS:= 'WM_MEASUREITEM';
      45 : strS:= 'WM_DELETEITEM';
      46 : strS:= 'WM_VKEYTOITEM';
      47 : strS:= 'WM_CHARTOITEM';
      48 : strS:= 'WM_SETFONT';
      49 : strS:= 'WM_GETFONT';
      50 : strS:= 'WM_SETHOTKEY';
      51 : strS:= 'WM_GETHOTKEY';
      55 : strS:= 'WM_QUERYDRAGICON';
      57 : strS:= 'WM_COMPAREITEM';
      65 : strS:= 'WM_COMPACTING';
      70 : strS:= 'WM_WINDOWPOSCHANGING';
      71 : strS:= 'WM_WINDOWPOSCHANGED';
      72 : strS:= 'WM_POWER';
      74 : strS:= 'WM_COPYDATA';
      75 : strS:= 'WM_CANCELJOURNAL';
      78 : strS:= 'WM_NOTIFY';
      80 : strS:= 'WM_INPUTLANGCHANGEREQUEST';
      81 : strS:= 'WM_INPUTLANGCHANGE';
      82 : strS:= 'WM_TCARD';
      83 : strS:= 'WM_HELP';
      84 : strS:= 'WM_USERCHANGED';
      85 : strS:= 'WM_NOTIFYFORMAT';
     123 : strS:= 'WM_CONTEXTMENU';
     124 : strS:= 'WM_STYLECHANGING';
     125 : strS:= 'WM_STYLECHANGED';
     126 : strS:= 'WM_DISPLAYCHANGE';
     127 : strS:= 'WM_GETICON';
     128 : strS:= 'WM_SETICON';
     129 : strS:= 'WM_NCCREATE';
     130 : strS:= 'WM_NCDESTROY';
     131 : strS:= 'WM_NCCALCSIZE';
     132 : strS:= 'WM_NCHITTEST';
     133 : strS:= 'WM_NCPAINT';
     134 : strS:= 'WM_NCACTIVATE';
     135 : strS:= 'WM_GETDLGCODE';
     160 : strS:= 'WM_NCMOUSEMOVE';
     161 : strS:= 'WM_NCLBUTTONDOWN';
     162 : strS:= 'WM_NCLBUTTONUP';
     163 : strS:= 'WM_NCLBUTTONDBLCLK';
     164 : strS:= 'WM_NCRBUTTONDOWN';
     165 : strS:= 'WM_NCRBUTTONUP';
     166 : strS:= 'WM_NCRBUTTONDBLCLK';
     167 : strS:= 'WM_NCMBUTTONDOWN';
     168 : strS:= 'WM_NCMBUTTONUP';
     169 : strS:= 'WM_NCMBUTTONDBLCLK';
     256 : strS:= 'WM_KEYDOWN';
     257 : strS:= 'WM_KEYUP';
     258 : strS:= 'WM_CHAR';
     259 : strS:= 'WM_DEADCHAR';
     260 : strS:= 'WM_SYSKEYDOWN';
     261 : strS:= 'WM_SYSKEYUP';
     262 : strS:= 'WM_SYSCHAR';
     263 : strS:= 'WM_SYSDEADCHAR';
     269 : strS:= 'WM_IME_STARTCOMPOSITION';
     270 : strS:= 'WM_IME_ENDCOMPOSITION';
     271 : strS:= 'WM_IME_COMPOSITION';
     272 : strS:= 'WM_INITDIALOG';
     273 : strS:= 'WM_COMMAND';
     274 : strS:= 'WM_SYSCOMMAND';
     275 : strS:= 'WM_TIMER';
     276 : strS:= 'WM_HSCROLL';
     277 : strS:= 'WM_VSCROLL';
     278 : strS:= 'WM_INITMENU';
     279 : strS:= 'WM_INITMENUPOPUP';
     287 : strS:= 'WM_MENUSELECT';
     288 : strS:= 'WM_MENUCHAR';
     289 : strS:= 'WM_ENTERIDLE';
     306 : strS:= 'WM_CTLCOLORMSGBOX';
     307 : strS:= 'WM_CTLCOLOREDIT';
     308 : strS:= 'WM_CTLCOLORLISTBOX';
     309 : strS:= 'WM_CTLCOLORBTN';
     310 : strS:= 'WM_CTLCOLORDLG';
     311 : strS:= 'WM_CTLCOLORSCROLLBAR';
     312 : strS:= 'WM_CTLCOLORSTATIC';
     512 : strS:= 'WM_MOUSEMOVE';
     513 : strS:= 'WM_LBUTTONDOWN';
     514 : strS:= 'WM_LBUTTONUP';
     515 : strS:= 'WM_LBUTTONDBLCLK';
     516 : strS:= 'WM_RBUTTONDOWN';
     517 : strS:= 'WM_RBUTTONUP';
     518 : strS:= 'WM_RBUTTONDBLCLK';
     519 : strS:= 'WM_MBUTTONDOWN';
     520 : strS:= 'WM_MBUTTONUP';
     521 : strS:= 'WM_MBUTTONDBLCLK';
     528 : strS:= 'WM_PARENTNOTIFY';
     529 : strS:= 'WM_ENTERMENULOOP';
     530 : strS:= 'WM_EXITMENULOOP';
     532 : strS:= 'WM_SIZING';
     533 : strS:= 'WM_CAPTURECHANGED';
     534 : strS:= 'WM_MOVING';
     536 : strS:= 'WM_POWERBROADCAST';
     537 : strS:= 'WM_DEVICECHANGE';
     544 : strS:= 'WM_MDICREATE';
     545 : strS:= 'WM_MDIDESTROY';
     546 : strS:= 'WM_MDIACTIVATE';
     547 : strS:= 'WM_MDIRESTORE';
     548 : strS:= 'WM_MDINEXT';
     549 : strS:= 'WM_MDIMAXIMIZE';
     550 : strS:= 'WM_MDITILE';
     551 : strS:= 'WM_MDICASCADE';
     552 : strS:= 'WM_MDIICONARRANGE';
     553 : strS:= 'WM_MDIGETACTIVE';
     560 : strS:= 'WM_MDISETMENU';
     561 : strS:= 'WM_ENTERSIZEMOVE';
     562 : strS:= 'WM_EXITSIZEMOVE';
     563 : strS:= 'WM_DROPFILES';
     564 : strS:= 'WM_MDIREFRESHMENU';
     641 : strS:= 'WM_IME_SETCONTEXT';
     642 : strS:= 'WM_IME_NOTIFY';
     643 : strS:= 'WM_IME_CONTROL';
     644 : strS:= 'WM_IME_COMPOSITIONFULL';
     645 : strS:= 'WM_IME_SELECT';
     646 : strS:= 'WM_IME_CHAR';
     656 : strS:= 'WM_IME_KEYDOWN';
     657 : strS:= 'WM_IME_KEYUP';
     768 : strS:= 'WM_CUT';
     769 : strS:= 'WM_COPY';
     770 : strS:= 'WM_PASTE';
     771 : strS:= 'WM_CLEAR';
     772 : strS:= 'WM_UNDO';
     773 : strS:= 'WM_RENDERFORMAT';
     774 : strS:= 'WM_RENDERALLFORMATS';
     775 : strS:= 'WM_DESTROYCLIPBOARD';
     776 : strS:= 'WM_DRAWCLIPBOARD';
     777 : strS:= 'WM_PAINTCLIPBOARD';
     778 : strS:= 'WM_VSCROLLCLIPBOARD';
     779 : strS:= 'WM_SIZECLIPBOARD';
     780 : strS:= 'WM_ASKCBFORMATNAME';
     781 : strS:= 'WM_CHANGECBCHAIN';
     782 : strS:= 'WM_HSCROLLCLIPBOARD';
     783 : strS:= 'WM_QUERYNEWPALETTE';
     784 : strS:= 'WM_PALETTEISCHANGING';
     785 : strS:= 'WM_PALETTECHANGED';
     786 : strS:= 'WM_HOTKEY';
     791 : strS:= 'WM_PRINT';
     792 : strS:= 'WM_PRINTCLIENT';
     896 : strS:= 'WM_PENWINFIRST';
     911 : strS:= 'WM_PENWINLAST';
    1024 : strS:= 'WM_PSD_PAGESETUPDLG';
    1025 : strS:= 'WM_PSD_FULLPAGERECT or WM_CHOOSEFONT_GETLOGFONT';
    1026 : strS:= 'WM_PSD_MINMARGINRECT';
    1027 : strS:= 'WM_PSD_MARGINRECT';
    1028 : strS:= 'WM_PSD_GREEKTEXTRECT';
    1029 : strS:= 'WM_PSD_ENVSTAMPRECT';
    1030 : strS:= 'WM_PSD_YAFULLPAGERECT';
//    1125 : strS:= 'WM_CHOOSEFONT_SETLOGFONT';
//    1126 : strS:= 'WM_CHOOSEFONT_SETFLAGS';

 1024 + 37 : strS:= 'EM_GETLIMITTEXT';
 1024 + 38 : strS:= 'EM_POSFROMCHAR';  // was in comments
 1024 + 39 : strS:= 'EM_CHARFROMPOS';  // was in comments
 1024 + 49 : strS:= 'EM_SCROLLCARET';
 1024 + 50 : strS:= 'EM_CANPASTE';        
 1024 + 51 : strS:= 'EM_DISPLAYBAND';     
 1024 + 52 : strS:= 'EM_EXGETSEL';        
 1024 + 53 : strS:= 'EM_EXLIMITTEXT';     
 1024 + 54 : strS:= 'EM_EXLINEFROMCHAR';  
 1024 + 55 : strS:= 'EM_EXSETSEL';        
 1024 + 56 : strS:= 'EM_FINDTEXT';        
 1024 + 57 : strS:= 'EM_FORMATRANGE';     
 1024 + 58 : strS:= 'EM_GETCHARFORMAT';   
 1024 + 59 : strS:= 'EM_GETEVENTMASK';    
 1024 + 60 : strS:= 'EM_GETOLEINTERFACE'; 
 1024 + 61 : strS:= 'EM_GETPARAFORMAT';   
 1024 + 62 : strS:= 'EM_GETSELTEXT';      
 1024 + 63 : strS:= 'EM_HIDESELECTION';   
 1024 + 64 : strS:= 'EM_PASTESPECIAL';    
 1024 + 65 : strS:= 'EM_REQUESTRESIZE';   
 1024 + 66 : strS:= 'EM_SELECTIONTYPE';   
 1024 + 67 : strS:= 'EM_SETBKGNDCOLOR';   
 1024 + 68 : strS:= 'EM_SETCHARFORMAT';   
 1024 + 69 : strS:= 'EM_SETEVENTMASK';    
 1024 + 70 : strS:= 'EM_SETOLECALLBACK';  
 1024 + 71 : strS:= 'EM_SETPARAFORMAT';   
 1024 + 72 : strS:= 'EM_SETTARGETDEVICE'; 
 1024 + 73 : strS:= 'EM_STREAMIN';
 1024 + 74 : strS:= 'EM_STREAMOUT';
 1024 + 75 : strS:= 'EM_GETTEXTRANGE';
 1024 + 76 : strS:= 'EM_FINDWORDBREAK';
 1024 + 77 : strS:= 'EM_SETOPTIONS';
 1024 + 78 : strS:= 'EM_GETOPTIONS';
 1024 + 79 : strS:= 'EM_FINDTEXTEX';
 1024 + 80 : strS:= 'EM_GETWORDBREAKPROCEX';
 1024 + 81 : strS:= 'EM_SETWORDBREAKPROCEX';

{ Richedit v2.0 messages }

 1024 + 82 : strS:= 'EM_SETUNDOLIMIT';
 1024 + 84 : strS:= 'EM_REDO';
 1024 + 85 : strS:= 'EM_CANREDO';
 1024 + 86 : strS:= 'EM_GETUNDONAME';
 1024 + 87 : strS:= 'EM_GETREDONAME';
 1024 + 88 : strS:= 'EM_STOPGROUPTYPING';
 1024 + 89 : strS:= 'EM_SETTEXTMODE';
 1024 + 90 : strS:= 'EM_GETTEXTMODE';

{ for use with EM_GET/SETTEXTMODE }

 1024 + 91 : strS:= 'EM_AUTOURLDETECT';
 1024 + 92 : strS:= 'EM_GETAUTOURLDETECT';
 1024 + 93 : strS:= 'EM_SETPALETTE';
 1024 + 94 : strS:= 'EM_GETTEXTEX';
 1024 + 95 : strS:= 'EM_GETTEXTLENGTHEX';

{ Far East specific messages }
 1024 + 100 : strS:= 'WM_CHOOSEFONT_SETLOGFONT & EM_SETPUNCTUATION';
 1024 + 101 : strS:= 'WM_CHOOSEFONT_SETFLAGS & EM_GETPUNCTUATION';
 1024 + 102 : strS:= 'EM_SETWORDWRAPMODE';
 1024 + 103 : strS:= 'EM_GETWORDWRAPMODE';
 1024 + 104 : strS:= 'EM_SETIMECOLOR';
 1024 + 105 : strS:= 'EM_GETIMECOLOR';
 1024 + 106 : strS:= 'EM_SETIMEOPTIONS';
 1024 + 107 : strS:= 'EM_GETIMEOPTIONS';
 1024 + 108 : strS:= 'EM_CONVPOSITION';

 1024 + 120 : strS:= 'EM_SETLANGOPTIONS';
 1024 + 121 : strS:= 'EM_GETLANGOPTIONS';
 1024 + 122 : strS:= 'EM_GETIMECOMPMODE';

   else if (wMsg >= WM_USER) then
               strS:='WM_USER + ' + IntToStr(wMsg - WM_USER,0)
        else   strS:='??? ' + IntToStr(wMsg,0) + ' ???';
   end;  // case wMsg of

DBMsgToStr:=strS;
end;  // DBMsgToStr

function DBNotifToStr(lNotif:longint):ShortString;
//================================================
{ Converts a notification message number into the corresponding
  notification message string, used in windows.
  Only for some notifications. The EN_notifications.
  -------------------------------------------------------}
var strS : string[50];
begin
case lNotif of
    // notifications received in a WM_Notify
    // Common to all controls.
      -1 : strS:= 'NM_OUTOFMEMORY or CBN_ERRSPACE';
      -2 : strS:= 'NM_ClICK';
      -3 : strS:= 'NM_DBLCLK';
      -4 : strS:= 'NM_RETURN';
      -5 : strS:= 'NM_RCLICK';
      -6 : strS:= 'NM_RDBLCLK';
      -7 : strS:= 'NM_SETFOCUS';
      -8 : strS:= 'NM_KILLFOCUS';

       0 : strS:='BN_CLICKED';
       1 : strS:='CBN_SELCHANGE or BN_PAINT';
       2 : strS:='CBN_DBLCLK or BN_PUSHED';
       3 : strS:='CBN_SETFOCUS or BN_UNPUSHED or BN_UNHILITE';
       4 : strS:='CBN_KILLFOCUS or BN_DISABLE';
       5 : strS:='CBN_EDITCHANGE or BN_DOUBLECLICKED';
       6 : strS:='CBN_EDITUPDATE or BN_SETFOCUS';
       7 : strS:='CBN_DROPDOWN or BN_KILLFOCUS';
       8 : strS:='CBN_CLOSEUP';
       9 : strS:='CBN_SELENDOK';
      10 : strS:='CBN_SELENDCANCEL';

       // Buttons messages.
       240 : strS:='BM_GETCHECK';
       241 : strS:='BM_SETCHECK';
       242 : strS:='BM_GETSTATE';
       243 : strS:='BM_SETSTATE';
       244 : strS:='BM_SETSTYLE';
       245 : strS:='BM_CLICK';
       246 : strS:='BM_GETIMAGE';
       247 : strS:='BM_SETIMAGE';

    // notifications received in a WM_Command
     256 : strS:= 'EN_SETFOCUS';
     512 : strS:= 'EN_KILLFOCUS';
     768 : strS:= 'EN_CHANGE';
    1024 : strS:= 'EN_UPDATE';
    1280 : strS:= 'EN_ERRSPACE';
    1281 : strS:= 'EN_MAXTEXT';
    1282 : strS:= 'EN_HSCROLL';
    1283 : strS:= 'EN_VSCROLL';

    // notifications received in a WM_Notify
    1792 : strS:= 'EN_MSGFILTER';
    1793 : strS:= 'EN_REQUESTRESIZE';
    1794 : strS:= 'EN_SELCHANGE';
    1795 : strS:= 'EN_DROPFILES';
    1796 : strS:= 'EN_PROTECTED';
    1797 : strS:= 'EN_CORRECTTEXT';
    1798 : strS:= 'EN_STOPNOUNDO';
    1799 : strS:= 'EN_IMECHANGE';
    1800 : strS:= 'EN_SAVECLIPBOARD';
    1801 : strS:= 'EN_OLEOPFAILED';
    1802 : strS:= 'EN_OBJECTPOSITIONS';
    1803 : strS:= 'EN_LINK';
    1804 : strS:= 'EN_DRAGDROPDONE';
    else strS:='??? ' + IntToStr(lNotif,0) + ' ???';
    end; // case

DBNotifToStr:=strS;
end;  // DBNotifToStr

procedure DBWaitSec(nSec:integer);
//================================
// Waits nSec before continuing
var
  rMsg        : MSG; // read messages from the keyboard
  wStart,
  wEnd,
  wSecurity   // security not to stay in the loop witout end
              : DWord;

begin
rMsg.message:=0;
if (nSec = 0) then begin
   // wait for a key to be pressed.
   repeat
      PeekMessage( @rMsg, 0, // any messages for this application
                   WM_KEYFIRST, WM_KEYLAST, // only keyboard messages
                   PM_REMOVE); // remove the message from the queue
      until (rMsg.message = WM_KEYUP);
   exit;
   end;

// Wait nSec seconds, or until a key is pressed.
wStart := GetTickCount;  // Time in milisecond when the computer was started
wSecurity:=0;
repeat
   wEnd:=GetTickCount;
   inc(wSecurity);
   PeekMessage( @rMsg, 0, // any messages for this application
                WM_KEYFIRST, WM_KEYLAST, // only keyboard messages
                PM_REMOVE); // remove the message from the queue

   until ((abs(wEnd - wStart) div 1000) >= nSec) or (rMsg.message = WM_KEYUP) or
         (wSecurity > 400000000);

end;  // DBWaitSec

procedure DBShowMemoryInfo(wMask:word);
//=====================================
// Gives some informations about memory status
// Writes the data in the debug window
var
  Buffer : MEMORYSTATUS;

begin
Buffer.dwLength:=SizeOf(MEMORYSTATUS); // should be set before calling GlobalMemoryStatus
GlobalMemoryStatus(@Buffer); // to get information about the memory available.

DBW0(wMask, '------------------');
DBW0(wMask, 'percent of memory in use =' + ITS(Buffer.dwMemoryLoad));
DBW0(wMask, 'bytes of physical memory' + ITS(Buffer.dwTotalPhys));
DBW0(wMask, 'free physical memory bytes' + ITS(Buffer.dwAvailPhys));
DBW0(wMask, 'bytes of paging file' + ITS(Buffer.dwTotalPageFile));
DBW0(wMask, 'free bytes of paging file' + ITS(Buffer.dwAvailPageFile));
DBW0(wMask, 'user bytes of address space' + ITS(Buffer.dwTotalVirtual));
DBW0(wMask, 'free user bytes' + ITS(Buffer.dwAvailVirtual));

end;  // DBGetMemoryInfo

procedure DBW0(lMask:longint; strS:ShortString);
//==============================================
{ procedure used to write text in a debugging window
  if lMask = 0 => everything is written
------------------------------------------------------}
var
//  nUnused     : integer; // to avoid error in DevPascal while compiling
  lLen        : longint; // length of text in the edit control
begin
if ((lMask and gllMask) <> 0) then exit;

// cannot write info while the debugging window is beeing created
// cannot be reentered while creation is in process.
if glfWhileInit then begin MessageBeep(0); exit; end;

if (not gglfDBInitDone) then begin
   glfWhileInit:=TRUE;

   // register the 'WinDeb' window if needed
   if (not glfRegistered) and (Not WinRegister) then begin
      MessageBox (0,'Register failed',NIL, mb_Ok);
      glfWhileInit:=FALSE;
      exit;
      end
   else begin
      glfRegistered:=TRUE;
      WinCreate;  // create the debugging window
      if (longint(glhWindow) = 0) then begin
         MessageBox (0,'WinCreate failed',NIL,MB_OK);
         glfWhileInit:=FALSE;
         exit;
         end
      else begin
         glhEdit := EditCreate; // create the Edit window, which is inside the debugging window
//         SetFocus(glhEdit); do not give the focus to the created debbuging window
         end;
      end;

   gglfDBInitDone:=TRUE;
   glfWhileInit:=FALSE;
   end;

if (lMask = 0) and (strS = '') then exit;  // noting is written.

// if Edit buffer is full, empty some characters at the beginning
lLen := GetWindowTextLength(glhEdit);
if (lLen > 27000) then begin
   // to delete, must be in read-write mode
   SendMessage(glhEdit, EM_SetReadOnly, 0 {0=Read-Write.}, 0);

   // select part of the text, delete it and goes to the end
   SendMessage(glhEdit, em_SetSel, 0, 2000);
   SendMessage(glhEdit, wm_Clear, 0, 0);
   SendMessage(glhEdit, em_SetSel, -1, -1);

   // back to the original read-write state.
//   SendMessage(glhEdit, EM_SetReadOnly, integer(fReadOnly), 0);
   end;

// if the mask number has to be written at the end of the string
if glfShowMaskNumber then
   strS:=strS + ' (' + IntToStr(lMask, 0) + ')';

// add return linfeed at the end of the string, plus #0 to indicate the end of the string
strS:=strS + #13 + #10 + #0;
SendMessage(glhEdit, em_SetSel, 100000000, 100000000); // add the string at the end of the text
SendMessage(glhEdit, em_ReplaceSel, 0, longint(@strS[1]));
end;  // DBW0

procedure DBW(lMask:longint; strS:Shortstring);
//=============================================
// Same as DBW0
begin
DBW0(lMask, strS);
end;  // DBW

initialization
  LoadPositionAndSize;

finalization
  // To save the position, size etc. of the debugging window.
  // If it is not called here, these parameters will only be saved
  // when the debugging window is closed by the user.
  DBSavePositionAndSize;


end.
