Einzelnen Beitrag anzeigen

Benutzerbild von MacGuyver
MacGuyver

Registriert seit: 9. Sep 2003
Ort: Wildeshausen
295 Beiträge
 
Turbo Delphi für Win32
 
#1

Konvertiere TP7 zu Delphi

  Alt 15. Sep 2010, 22:59
Moin Leute

Wie schon länger angekündigt möchte ich nun meine Konvertierung von Turbo-Pascal 7.0 in Delphi vorstellen. Das ist mein Meilenstein in der DP. Es gibt bestimmt noch so ein paar arme Schweine wie ich, die so ein altes grottiges Ding pflegen müssen. Für mich war es eine Menge Arbeit, bis meine Anwendung entlich als Konsole lief. Ich erzähle mal nicht von den vielen Stolpersteinen sondern von dem Weg, den man gehen muss. Es lohnt sich auf jeden Fall. Unter Delphi hat man die ganzen Begrenzungen nicht, die unter DOS so waren. Reichlich Speicher, deutlich näher an 32 Bit, den Drucker direkt ansprechen ohne Zwischenprogramm, uswusf.

Der erste Akt: FindFirst/FindNext/FindClose
Hätte ich die ganzen Stellen mit Compilerschaltern versehen, wäre ich heute noch dabei. Also habe ich alle Stellen so umgestellt, dass fast alles über dieses Objekt läuft.
Delphi-Quellcode:
type
  TDirInfo = object
{$IfDef Win32}
  private
    FDoFindClose : Boolean;
  public
{$EndIf}
    DirInfo : TSearchRec;

    constructor Create;

    function FindFirst( aDatei : PathStr;
                           aAttr : Word):Boolean;

    function FindNext:Boolean;

    destructor Free;
  end;

constructor TDirInfo.Create;

begin
{$IfDef Win32}
  FDoFindClose := False;
{$EndIf}
end;

function TDirInfo.FindFirst( aDatei : PathStr;
                             aAttr : Word):Boolean;
{$IfDef Win32}
var
  lEc : Int32;
{$EndIf}

begin
{$IfDef Win32}
  if FDoFindClose then
    SysUtils.FindClose(DirInfo);
  lEc := SysUtils.FindFirst(aDatei,aAttr,DirInfo);
  if lEc = 0 then
  begin
    FDoFindClose := True;
    FindFirst := True;
  end
  else
  begin
    FindFirst := False;
  end;
{$Else}
  Dos.FindFirst(aDatei,aAttr,DirInfo);
  FindFirst := DosError = 0;
{$EndIf}
end;

function TDirInfo.FindNext:Boolean;

{$IfDef Win32}
var
  lEc : Int32;
{$EndIf}

begin
{$IfDef Win32}
  lEc := SysUtils.FindNext(DirInfo);
  FindNext := lEc = 0;
{$Else}
  Dos.FindNext(DirInfo);
  FindNext := DosError = 0;
{$EndIf}
end;

destructor TDirInfo.Free;

begin
{$IfDef Win32}
  if FDoFindClose then
    SysUtils.FindClose(DirInfo);
{$EndIf}
end;
In diesem kleinen Anfang merken einige von euch, wohin der Hase läuft. Es gibt ein paar Stellen dann nur noch wo man mit Kompilerschaltern arbeiten muss.

Die Variable InOutRes gibt es unter Delphi nicht. Hier gibt es aber die Prozedur SetInOutRes die ich dann überall verwende. So ist sie dann im TP eingebunden. Das Umstellen des Quelltextes von InOutRes auf SetInOutRes übernimmt dann die Konvertierung. Dazu später mehr.
Delphi-Quellcode:
{$IfNDef Win32}
procedure SetInOutRes( aEc : Int_Int);

begin
  InOutRes := aEc;
end;
{$EndIf}
Der zweite Akt: Fail in Konstruktoren
Ein Konstruktor darf nur aus Speichermangel in das Fail laufen. Ich hatte das für allmöglichen Kram genutzt. Das wird jetzt reine Handarbei. Ich bin einfach dabeigegangen und habe alle Stellen mit "{ok}" markiert, wo das Fail durch einen Speichermangel ausgeführt werden könnte. Unter Delphi passiert das eh nicht, da gibt es kein MemAvail und MaxAvail. Unter Kompilerschalter habe ich die Funktionen selbst geschrieben und einfach Max(Int32) übergeben. Die nativen Typen erkläre ich gleich. Alle anderen Stellen müssen so überarbeitet werden, dass das Fail rausfliegt. Einfach den Konstruktor mit weniger Parameter aufrufen und eine weitere Funktion mit der extrahierten Arbeit beauftragen. Ja, das kann verdammt viel werden und lange dauern.

Der dritte Akt: Auf Funktionalität verzichten
Ich habe Modemgeschichten und Grafikausgaben einfach deaktiviert. Falls jemand diesen Teil noch braucht, ist das kein Problem. Ich kann mein FOS als DOS- und Win32-Applikation kompilieren. Wer den alten "Mist" noch braucht, soll das DOS-Programm starten. Beim deaktivieren Kompilerschalter verwenden!

Der vierte Akt: Die Hauptdatei
In der Hauptdatei sind nur noch die Uses-Anweisung, ein Include-Aufruf und im Programmblock der Start der Anwendung. Auf diese Art wird dann später auch die DPR erstellt.

So sieht jetzt die PAS-Datei aus:
Delphi-Quellcode:
program FOSdos;

{$M 65500,0,655360}

uses FosOver,Overlay,
     FosChars,Crt,Dos,Fosmenue,Fostast,Fosfiles,Fosunter,
     Fosan,Fosbuch,Foscheck,Fosmanam,Fospersm,Fosterm,Fosakt,Fosmastm,
     Fostunde,Fosgrund,FosGrun2,Foslizen,FosMBox,FosRout,FosDyna,FosBase,
     FosRout2,FosRout3,FosObj,FosAbsch,
     FosMUnit,
     FosTEdit,FosBrows,FoStatik,
     FosInput,Netzwerk,FosGlob,FoSchon,FosMonov,FoSerie,FosBitL,
     FosDebug,
     FosDump,
     FosRes,fosdatum,FosDialo,FoSicher,FosPrint,FosBruch,
     FosCMD,FoShell,FosTime,FosMask,Fos2dStr,FosKMenu,FosArchi,FosAn2,
     FosWork,FosXMS,FosNInfo,Drucken,Killer,PipeStr,DruckObj,Vorbest,
     HeapUse,
     {$IFNDEF DPMI}
     ShowHeap,
     {$ENDIF DPMI}
     Einstell,KeyLoop,Kasse,Connect,Mouse,
     Vorlagen,BestWerb,Ortsteil,Bondruck,Kalender,Tastatur,RecBaseU,
     FosMPack;

{$O ShowHeap.Pas}
{$O GDISupp.Pas }
{$O FosLZSS.Pas }
{$O FORMULAR.PAS}
{$O FOSDIALO.PAS}
{$O FOSOBJ.PAS  }
{$O FosInput.Pas}
{$O FosWork     }
{$O FoSerie.Pas }
{$O FOSABSCH.PAS}
{$O FOSAKT.PAS  }
{$O FOSAN.PAS   }
{$O FOSAN2.PAS  }
{$O FOSARCHI.PAS}
{$O FOSBASE.PAS }
{$O FosBitL.Pas }
{$O FOSBROWS.PAS}
{$O FosBruch.Pas}
{$O FOSBUCH.PAS }
{$O FOSCHECK.PAS}
{$O FosCMD.Pas  }
{$O FosDebug.Pas}
{$O FosDump.Pas }
{$O FoShell.Pas }
{$O FoSicher.Pas}
{$O FOSLIZEN.PAS}
{$O Netzwerk.Pas}
{$O FOSMANAM.PAS}
{$O FOSMASTM.PAS}
{$O FOSMBOX.PAS }
{$O FosMCons.Pas}
{$O FOSMENUE.PAS}
{$O FosMHelp.Pas}
{$O FosMonoV.Pas}
{$O FosMPack.Pas}
{$O FosMUnit.Pas}
{$O FOSPERSM.PAS}
{$O FosPrint.Pas}
{$O FOSTAPEL.PAS}
{$O FoStatik.Pas}
{$O FosTEdit.Pas}
{$O FOSUNTER.PAS}
{$O FosMask.Pas }
{$O Fos2dStr    }
{$O FosKMenu    }
{$O FosXMS      }
{$O FosNInfo    }
{$O Drucken     }
{$O Killer      }
{$O DruckObj    }
{$O Vorbest     }
{$O Einstell    }
{$O Formular    }
{$O Kasse       }
{$O Connect     }
{$O Mouse       }
{$O Vorlagen    }
{$O BestWerb    }
{$O Ortsteil    }
{$O Tastatur    }
{$O Kalender    }
{$O KMenu2      }
{$O Bondruck    }
{$O FosRes      }
{$O FOSFILES.PAS}
{$O Fostunde    }
{$O PipeStr     }


{$I Fosystem.Inc}

begin
  Haupt;
end.
Und ein Einblick in die DPR-Datei:
Delphi-Quellcode:
program Fosystem;

{$APPTYPE CONSOLE}

uses {$IfDef Win32}SysUtils,FosDelphi,{$EndIf}
     BestWerb in 'BestWerb.pas',
     Bondruck in 'Bondruck.pas',
     Connect in 'Connect.pas',
     Crt in '.\Units\Crt.pas',
     Dos in '.\Units\Dos.pas',
     Drucken in 'Drucken.pas',
     DruckObj in 'DruckObj.pas',
     Einstell in 'Einstell.pas',
     Formular in 'Formular.pas',
     Fos2dStr in 'Fos2dStr.pas',
     Fosabsch in 'Fosabsch.pas',
     Fosakt in 'Fosakt.pas',
     Fosan in 'Fosan.pas',
     Fosan2 in 'Fosan2.pas',
     Fosarchi in 'Fosarchi.pas',
     Fosbase in 'Fosbase.pas',
     FosBitL in 'FosBitL.pas',
     FosBrows in 'FosBrows.pas',
     FosBruch in 'FosBruch.pas',
     Fosbuch in 'Fosbuch.pas',
     Foschars in 'Foschars.pas',
     Foscheck in 'Foscheck.pas',
     FoSchon in 'FoSchon.pas',
     FosCMD in 'FosCMD.pas',
     FosDatum in 'FosDatum.pas',
     FosDebug in 'FosDebug.pas',
     FosDialo in 'FosDialo.pas',
     FosDyna in 'FosDyna.pas',
     FoSerie in 'FoSerie.pas',
     Fosfiles in 'Fosfiles.pas',
     FosGlob in 'FosGlob.pas',
     FosGrun2 in 'FosGrun2.pas',
     FosGrund in 'FosGrund.pas',
     FoShell in 'FoShell.pas',
     Fosicher in 'Fosicher.pas',
     FosInput in 'FosInput.pas',
     FosKMenu in 'FosKMenu.pas',
     Foslizen in 'Foslizen.pas',
     Fosmanam in 'Fosmanam.pas',
     FosMask in 'FosMask.pas',
     Fosmastm in 'Fosmastm.pas',
     FosMBox in 'FosMBox.pas',
     Fosmenue in 'Fosmenue.pas',
     FosMonoV in 'FosMonoV.pas',
     FosNInfo in 'FosNInfo.pas',
     FosObj in 'FosObj.pas',
     Fospersm in 'Fospersm.pas',
     FosPrint in 'FosPrint.pas',
     FosRes in 'FosRes.pas',
     FosRout in 'FosRout.pas',
     FosRout2 in 'FosRout2.pas',
     FosRout3 in 'FosRout3.pas',
     FoStapel in 'FoStapel.pas',
     Fostast in 'Fostast.pas',
     FoStatik in 'FoStatik.pas',
     FosTEdit in 'FosTEdit.pas',
     Fosterm in 'Fosterm.pas',
     FosTime in 'FosTime.pas',
     Fostunde in 'Fostunde.pas',
     Fosunter in 'Fosunter.pas',
     FoSWork in 'FoSWork.pas',
     GDISupp in 'GDISupp.pas',
     Graph in '.\Units\Graph.pas',
     HeapUse in 'HeapUse.pas',
     Kalender in 'Kalender.pas',
     Kasse in 'Kasse.pas',
     KeyLoop in 'KeyLoop.pas',
     Killer in 'Killer.pas',
     KMenu2 in 'KMenu2.pas',
     Mouse in 'Mouse.pas',
     Netzwerk in 'Netzwerk.pas',
     Ortsteil in 'Ortsteil.pas',
     PipeStr in 'PipeStr.pas',
     Printers,
     RecBase in 'P:\RecBase\RecBase.pas',
     RecBaseU in 'RecBaseU.pas',
     SListDOS in 'SListDOS.pas',
     Statik2 in 'Statik2.pas',
     Tastatur in 'Tastatur.pas',
     Vorbest in 'Vorbest.pas',
     Vorlagen in 'Vorlagen.pas',
     Windows,
     XmsEmu in '.\Units\XmsEmu.pas';

{$I Fosystem.Inc}

var
  lCount : Int32;
  lTicks : DWord;

begin
  lCount := Printer.Printers.Count;
  if lCount > 0 then
  begin
    lTicks := GetTickCount;
    if lTicks < 3974400000 then
                {46 Tage * 24 Stunden * 60 Minuten * 60 Sekunden  * 1000}
    begin
      try
        Haupt;
      except
        on E:Exception do
        begin
          MessageDlg(symStop
                    ,'Exception aufgetreten (' + E.ClassName + '):'#13
                    +BreakStrToStrList(AnsiToAscII(E.Message),70,255)
                    ,mdxEnter + mdxEsc
                    ,mdpMitte);
        end;
      end;
    end
    else
    begin
      WriteLn('Der Rechner l' + _aumlk + 'uft schon l' + _aumlk
             +'nger als 45 Tage. Bitte neu starten.');
      Write('Enter dr' + _uumlk + 'cken...');
      ReadLn;
    end;
  end
  else
  begin
    WriteLn('Es ist kein Drucker unter Windows installiert!');
    Write('Enter dr' + _uumlk + 'cken...');
    ReadLn;
  end;
end.
Schön zu sehen ist die Prüfung auf mindestens einen installierten Drucker und dass GetTickCount nicht überläuft. Auch schön zu sehen, wie ich mit Umlauten umgehe. Die Konvertierung stellt alle Sonderzeichen als Konstante dar.

Der fünfte Akt: XMS-Speicher
Unter Delphi werden die DOS-Funktionen nicht unterstützt. Da ich über ein Objekt den Speicher verwendet habe, arbeitet mein Delphi-Objekt einfach mit Heap-Speicher und tut so, als ob es XMS sein. Dem Programm ist das egal,
hauptsache es läuft wie vorher.



So, grobe Vorarbeit ist getan. Mit den Umstellungen und vielleicht ein paar Erneuerungen kann man locker ein Release ausliefern, das Ding läuft genauso wie vorher.

Verwendete Typen: Das Dilemma kennen sicherlich einige, die Source für TP und Delphi schreiben mussten. Ich habe das mit klaren Typen umschifft.
Delphi-Quellcode:
{$IfDef Win32}
    Int16 = SmallInt;
    Int32 = Integer;
    Word_Int = Integer;
    Int_Int = Integer;
    Int32_Cardinal = Cardinal;
{$Else}
    Int16 = Integer;
    Int32 = LongInt;
    Word_Int = Word;
    Int_Int = Integer;
    ShortString = string;
    Int32_Cardinal = LongInt;
    TSearchRec = SearchRec;
    TFileRec = FileRec;
    TextFile = Text;
{$EndIf}
Jetzt höre ich schon einen Aufschrei! Ist der bekloppt? Weiß der, wie oft diese Typen verwendet wurden?
KLAR! Die Umstellung übernimmt die Konvertierung. Schon sieht das ganze viel geschmeidiger aus. Es bedarf natürlich eine Menge Handarbeit. SetInOutRes() will in Dos Int16 und in Delphi Int32 haben. Über den Typ Int_Int(vor dem Unterstrich DOS, hinter dem Unterstrich Delphi) ist das simpel gelöst.

Was ist mit den DOS-Units?

Crt.pas gibt es im Netz. Wo ich meine gefunden habe, weiß ich nicht mehr. In der Unit steht das drin:
Delphi-Quellcode:
(*-------------------------------------------------------------------------
Portions Copyright (c) 1988-2003 Borland Software Corporation
Portions Copyright (c) 2006-2009 W.Ehrhardt

Disclaimer:
===========
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.

If you use this code, please credit me and keep the references to the other
authors and sources.


Description:
============

This unit is a light version of Will DeWitt's code with several bug fixes
(especially readkey, extended key codes etc). Will's 'unit was based heavily
off of the Borland CBuilder 5 RTL'. Because of the unclear licence status of
Will's unit, my CRT source is not under zlib license.

Anyway, in this unit the code from Will/Borland is radically rewritten and
rearranged. The guiding requirement was to make it almost BP7 compatible.

The basic idea for separate hardware/software sound support is from Rudy
Velthuis' freeware console, but the implementation is different.

The supported keys for line editing are from BP7 (^A, ^H, ^D, ^F, ^M, ^S,
^Z), the paradigm shift from readkey to keypressed for doing the dirty work
is from FP. The key codes / translations / functionalities were taken from
the Phoenix BIOS book and a test program compiled with BP7.

There is still work to be done for some rare special extended keys, but this
work is delayed to bugfixes or problem reports.

-------------------------------------------------------------------------*)
DOS.pas habe ich selbst aufgesetzt:
Delphi-Quellcode:
unit DOS;

interface

type
  PathStr = string[79];
  DirStr = string[67];
  NameStr = string[8];
  ExtStr = string[4];

implementation

begin
end.
Graph.pas ist bei mir voll das fette Teil:
Delphi-Quellcode:
unit Graph;

interface

implementation

end.
Die sollte man vor dem ersten Kompilieren unter Delphi anlegen. Ich hatte zum Anfang überall die Aufrufe mit Kompilerschalter versehen, bis ich auf die Idee mit den leeren Units gekommen bin.



Ich hänge die Konvertierung einfach mal komplett dran. Ich habe zum Anfang von einem Ordner in einen anderen Konvertiert. So konnte ich immer wieder in beiden Systemen kompilieren und Stück für Stück nacharbeiten. Unter TP ist dabei das führende System. Ich habe auch mal ein Stück unter Delphi programmiert. Wenn das dann in Ordnung war, habe ich das gleich in den Dosen-Source eingebaut, um die Konsistenz zu wahren.



Ich wünsche Viel Spaß bei der Umstellung

Stefan
Angehängte Dateien
Dateityp: rar CvtTP7toDelphi.rar (10,3 KB, 5x aufgerufen)
Englisch eine Weltsprache? Zu kompliziert und der nahe Osten würde Englisch als Pflichtweltsprache nicht akzeptieren.
IDO wäre genau das Richtige: http://forum.idolinguo.de/index.php oder www.idolinguo.de
  Mit Zitat antworten Zitat