Difference between revisions of "Multiplatform Programming Guide/de"

From Lazarus wiki
Jump to navigationJump to search
 
(21 intermediate revisions by 8 users not shown)
Line 1: Line 1:
 
{{Multiplatform Programming Guide}}
 
{{Multiplatform Programming Guide}}
 +
<br>
 +
Zurück zu den [[Additional information/de|Zusätzlichen Informationen]].<br>
 +
<br>
 +
Diese Seite ist der Beginn einer Einführung die das Hauptaugenmerk auf die Erstellung von Multiplattformanwendungen mit Lazarus richtet. Es werden die notwendigen Vorkehrungen, ein Programm portabel zu halten und auch der Portierungsprozess eines bereits bestehenden Programms betrachtet. Ich lade den Leser dazu ein, diesen Artikel zu erweitern.
  
Diese Seite ist der Beginn einer Einführung die das Hauptaugenmerk auf die Erstellung von Multiplattformanwendungen mit Lazarus richtet. Es werden die notwendigen Vorkehrungen, ein Programm portabel zu halten und auch der Portierungsprozess eines bereits bestehenden Programmes betrachtet. Ich lade den Leser dazu ein, diesen Artikel zu erweitern.
 
  
 
__TOC__
 
__TOC__
Line 7: Line 10:
 
== Einführung in die Multiplattform Programmierung ==
 
== Einführung in die Multiplattform Programmierung ==
  
=== Welche Betriebssysteme sollen abgedeckt werden? ===
+
=== Welche Betriebssysteme sollen unterstützt werden? ===
  
 
Um diese Frage zu beantworten, müssen sie ermitteln, wer ihre potentiellen Nutzer sind und wie ihr Programm genutzt werden soll. Die Antwort auf diese Frage hängt davon ab, wo sie ihre Programm einsetzen möchten.
 
Um diese Frage zu beantworten, müssen sie ermitteln, wer ihre potentiellen Nutzer sind und wie ihr Programm genutzt werden soll. Die Antwort auf diese Frage hängt davon ab, wo sie ihre Programm einsetzen möchten.
  
Zum Beispiel Europa: Wenn sie eine Desktop-Anwendung entwickeln, können sie entscheiden, dass es nur für Windows und OS X Sinn macht. OS X ist das populärste Unix der Welt und strömt auf Desktops, wohingegen Linux meist dort herausgezögert wird. Bedenken sie die 100:10:1 Regel, die besagt, dass in jeder größeren Organisation oder Benutzergruppe es nicht ungewöhnlich ist, Windows, OS X und Linux Arbeitsplätze in eben jener Aufteilung zu finden.
+
Zum Beispiel Europa: Wenn sie eine Desktop-Anwendung entwickeln, können sie entscheiden, dass es nur für Windows und OS X Sinn macht. OS X ist das populärste Unix der Welt und strömt auf Desktops, wohingegen Linux meist dort heraus gezögert wird. Bedenken sie die 100:10:1 Regel, die besagt, dass in jeder größeren Organisation oder Benutzergruppe es nicht ungewöhnlich ist, Windows, OS X und Linux Arbeitsplätze in eben jener Aufteilung zu finden.
  
 
An anderen Orten wie beispielsweise Südamerika ist Windows größtenteils marktbeherrschend, wohingegen Linux als Dekstop Plattform aufstrebt und in einigen großen Marktketten fast gleich mit Windows verkauft wird. OS X wird hauptsächlich im Audio- und Videobereich eingesetzt.
 
An anderen Orten wie beispielsweise Südamerika ist Windows größtenteils marktbeherrschend, wohingegen Linux als Dekstop Plattform aufstrebt und in einigen großen Marktketten fast gleich mit Windows verkauft wird. OS X wird hauptsächlich im Audio- und Videobereich eingesetzt.
  
Ist die handvoll OS X und Linux Nutzer den extra Portierungsaufwand der zum Entwickeln, Packen, Verteilen und Supporten benötigt ist, wert? Ein klares ja, wenn es das Projekt es verlangt. Oder wenn der mehr benötigte Aufwand gering ist, wird die Antwort ebenso warscheinlich ja sein. Wenn sie sie aus Prinzip unterstützen, wird die Antwort auch ja sein, solange der extra Aufwand nicht als Hinderungsgrund zur Fertigstellung des Projektes steht.
+
Ist die Hand voll OS X und Linux Nutzer den extra Portierungsaufwand wert, der zum Entwickeln, Packen, Verteilen und Supporten benötigt ist? Ein klares ja, wenn es das Projekt es verlangt. Oder wenn der mehr benötigte Aufwand gering ist, wird die Antwort ebenso wahrscheinlich ja sein. Wenn sie sie aus Prinzip unterstützen, wird die Antwort auch ja sein, solange der extra Aufwand nicht als Hinderungsgrund zur Fertigstellung des Projektes steht.
  
 
Wenn sie Software entwickeln, die auf einem Webserver laufen soll, ist die am meisten genutzte Plattform Unix. In diesem Fall ist es sinnvoll, Linux, Solaris, *BSD und andere Unix-Derivate als Zielplattform anzusehen, wobei zum Teil auch Windows Server zum Einsatz kommen.
 
Wenn sie Software entwickeln, die auf einem Webserver laufen soll, ist die am meisten genutzte Plattform Unix. In diesem Fall ist es sinnvoll, Linux, Solaris, *BSD und andere Unix-Derivate als Zielplattform anzusehen, wobei zum Teil auch Windows Server zum Einsatz kommen.
Line 21: Line 24:
 
Wenn sie nur für eine Plattform entwickeln, werden vielleicht Free Pascal und Lazarus nicht die besten Mittel dafür sein, es sei denn, sie möchten sich die Möglichkeit offen halten, spätere Versionen ihrer Software auf andere Plattformen zu portieren. Wenn sie beispielsweise nur Windows Desktopanwendungen erstellen, könnte Delphi die bessere Alternative sein.
 
Wenn sie nur für eine Plattform entwickeln, werden vielleicht Free Pascal und Lazarus nicht die besten Mittel dafür sein, es sei denn, sie möchten sich die Möglichkeit offen halten, spätere Versionen ihrer Software auf andere Plattformen zu portieren. Wenn sie beispielsweise nur Windows Desktopanwendungen erstellen, könnte Delphi die bessere Alternative sein.
  
Once you've mastered cross-platform development, you can usually just focus on the problem the software is designed to solve and do most of your development on whatever platform your have available or feel most comfortable with. That is, once you've addressed any cross-platform issues in your design, you can largely ignore the other platforms, much as you would when developing for a single platform. However, at some point you'll need to test deploying and running your program on the other platforms and it will be helpful to have unrestricted access to machines running the all target operating systems. If you don't want multiple physical boxes, you can look into configuring a dual-boot Windows-Linux box or running Windows and Linux on your Mac under an emulator like Virtual PC or iEmulator.
+
Sobald sie die Plattformunabhängigkeit gemeistert haben, können Sie sich normalerweise auf das Problem konzentrieren, für das die Software entworfen werden soll und die Hauptzeit der Entwicklung auf der Plattform verbringen, über die sie verfügen oder auf der sie sich am wohlsten fühlen.
 +
Sie können, sobald Sie die Fallstricke der Plattformunabhängigkeit in Ihrem Design erkannt haben, größtenteils die anderen Plattformen ignorieren, ebenso, als wenn sie für eine einzelne Plattform entwickeln würden.
  
==Der Portierungsvorgang zwischen Windows und Linux==
+
Jedoch kommen sie an einen Punkt, an dem sie die Verteilung und die Ausführung ihres Programms auf den anderen Plattformen testen müssen. Spätestens dann ist es hilfreich, unbegrenzten Zugriff auf Rechner mit ihren gewählten Zielplattformen zu haben.
  
===Windows API Funktionen===
+
Wenn Sie nicht mehrere PC's haben möchten, können Sie ein Dual-Boot System mit Windows und Linux konfigurieren oder Windows und Linux auf ihrem Mac in einem Emulator wie Virtual PC oder iEmulator laufen lassen.
  
 +
== Der Portierungsvorgang zwischen Windows und Linux ==
  
Viele Windows Programme nutzen extensiv die Windows API. In plattformübergreifenden Applikationen können diese Funktionen nicht direkt benutzt werden, sondern müssen in eine Kompilerdirektive eingeschlossen werden, z.b. {$IFDEF Win32}.
+
=== Windows API Funktionen ===
  
Glücklicherweise werden die meist genutzten Windows API Funktionen zur Verwendung in der Unit LCLIntf implementiert. Diese Unit kann die Lösung für Programme sein, die sehr stark die Windows API verwenden, obwohl die beste Lösung die Substitution dieser Aufrufe durch plattformübergreifende Komponenten der LCL ist. Sie können beispielsweise alle Aufrufe von GDI Zeichenfunktionen durch das TCanvas Objekt ersetzen.
 
  
===Dateisystemunterscheide===
+
Viele Windows Programme nutzen extensiv die Windows API. In plattformübergreifenden Anwendungen können diese Funktionen nicht direkt benutzt werden, sondern müssen in eine Kompilerdirektive eingeschlossen werden, z.B. {$IFDEF Win32}.
  
Einer besonderen Beobachtung für die Portierung von Applikationen zwischen Linux und Windows bedarf das Dateisystem. Unter Windows sind Dateinamen beispielsweise nicht Case-Sensitiv, wohingegen sie es unter Unix-Plattformen sind. Dies kann der Grund für eine Menge nervenraubender Fehler sein. Daher sollte jede portable Applikation konsistente Dateinamen verwenden.
+
Glücklicherweise werden die meist genutzten Windows API Funktionen zur Verwendung in der Unit LCLIntf implementiert. Diese Unit kann die Lösung für Programme sein, die sehr stark die Windows API verwenden, obwohl die beste Lösung der Austausch dieser Aufrufe durch plattformübergreifende Komponenten der LCL ist. Sie können beispielsweise alle Aufrufe von GDI Zeichenfunktionen durch das TCanvas Objekt ersetzen.
  
===Linux kennt kein "Programmverzeichnis"===
+
=== Dateisystemunterschiede ===
  
One concern when porting applications between Linux and Windows is the file system. Many programmers are used to call ExtractFilePath(ParamStr(0)) or Application.ExeName to get the location of the executable, and then search for the necessary files for the program execution (Images, XML files, database files, etc) based on the location of the executable. This is incorrect in Linux. The string on ParamStr(0) may not only not contain the directory of the executable, as it also varies between different shell programs (sh, bash, etc).
+
Einer besonderen Beobachtung für die Portierung von Applikationen zwischen Linux und Windows bedarf das Dateisystem. Unter Windows sind Dateinamen beispielsweise nicht case-sensitiv, wohingegen sie es unter Unix-Plattformen sind. Dies kann der Grund für eine Menge nervenraubender Fehler sein. Daher sollte jede portable Anwendung konsistente Dateinamen verwenden.
  
Even if Application.ExeName could in fact know the directory where the file under execution is, that file could be a symbolic link, so you would get the directory of the link instead.
+
=== Unix kennt kein "Programmverzeichnis" ===
  
So what should we do? On Linux you should use two different places to store configurations and resource files:
+
Eine Sorge, wenn man Anwendungen zwischen Linux und Windows portiert, ist das Dateisystem. Viele Programmierer sind gewöhnt, ExtractFilePath(ParamStr(0)) oder Application.ExeName aufzurufen um den Ort der ausführbaren Datei zu erhalten, und dann nach den notwendigen Dateien für die Programmausführung (Bilder, XML Dateien, Datenbankdateien, etc) zu suchen basierend auf dem Ort der ausführbaren Datei. Das ist falsch unter Linux. Die Zeichenkette bei ParamStr(0) kann nicht nur das Verzeichnis des executable enthalten, ebenso variiert es zwischen verschiedenen Shell-Programmen (sh, bash, etc).
  
* Resource files (i.e. images, help files)
+
Sogar wenn Application.ExeName tatsächlich wüsste, wo die ausgeführte Datei sich befindet, könnte es sich immer noch um einen symbolischen Link handeln und nur das Verzeichnis des Links würde verwendet werden.
  
A fixed privileged location for the executable and resource files which will not change.
+
Was kann man also machen? Unter Linux sollten Sie zwei verschiedene Orte verwenden, um Konfigurations- und Ressourcen-Dateien zu speichern:
  
This location can be something like: /usr/share/app_name or /opt/app_name
+
* Ressourcendateien (z.B. Bilder, Hilfedateien)
  
Most programs will be executed without root privileges and the fixed directory for a given application usually only available for the root user to write, so don't write on this directory. Only read information from it.
+
Ein festgelegtes, bevorzugtes Verzeichnis für ausführbare und Ressourcendateien, das unveränderlich ist.
  
* Configuration files
+
Das kann zum Beispiel sein: /usr/share/app_name oder /opt/app_name
  
You can use the [[doc:rtl/sysutils/getappconfigdir.html|GetAppConfigDir]] function from SysUtils unit to get a suitable place to store configuration files on different system. The function has one parameter, called Global. If it is True then the directory returned is a global directory, i.e. valid for all users on the system. If the parameter Global is false, then the directory is specific for the user who is executing the program. On systems that do not support multi-user environments, these two directories may be the same.
+
Die meisten Programme werden ohne Administrator/Root-Rechte ausgeführt werden und nur  Administrator/Root wird die Schreibrechte an dem für ein bestimmtes Programm definierten Verzeichnis besitzen. Schreiben Sie daher keine Daten in das Verzeichnis, sondern greifen Sie nur lesend darauf zu.
  
There is also the [[doc:rtl/sysutils/getappconfigfile.html|GetAppConfigFile]] witch will return an appropriate name for an application configuration file.
+
* Konfigurationsdateien
  
Here is an example of the output of those functions on different systems:
+
Sie können die Funktion [[doc:rtl/sysutils/getappconfigdir.html|GetAppConfigDir]] aus der Unit SysUtils verwenden, um einen geeigneten Ort zur Ablage der Konfigurationsdateien auf verschiedenen Systemen zu ermitteln. Diese Funktion besitzt den boolschen Parameter Global. Wenn dieser true ist, dann ist das zurückgegebene Verzeichnis ein "globales Verzeichnis", d.h. es betrifft alle Benutzer auf dem System. Wenn der Parameter Global false ist, dann ist das Verzeichnis spezifisch für den Benutzer, der es ausführt. Auf Systemen, die Mehrbenutzer-Umgebungen nicht unterstützen, kann es sich um ein und dasselbe Verzeichnis handeln.
  
<pre>
+
Es gibt auch [[doc:rtl/sysutils/getappconfigfile.html|GetAppConfigFile]], das einen geeigneten Namen für eine Anwendungs-Konfigurationsdatei zurückgibt. Diese Funktion benutzt denselben Parameter Global wie GetAppConfigDir. Zusätzlich kann dort der optionale Parameter SubDir verwendet werden, der ans Ende der Verzeichniskette ein eigenes Unterverzeichnis anfügt (SubDir ist per Voreinstellung False, d.h. GetAppConfigFile(true) ist dasselbe wie GetAppConfigFile(true, false).
 +
 
 +
Auf einem GNU/Linux-System ergeben die Aufrufe von GetAppConfigDir und GetAppConfigFile folgende Resultate:
 +
 
 +
  program MyProg;
 +
  (...)
 +
 
 +
  GetAppConfigDir('''true''');          ==>  '/etc/MyProg/'
 +
  GetAppConfigFile('''true''');          ==>  '/etc/MyProg.cfg'
 +
  GetAppConfigFile('''true, true''');    ==>  '/etc/MyProg/MyProg.cfg'
 +
 
 +
  GetAppConfigDir('''false''');          ==>  '/home/user/.config/MyProg/'
 +
  GetAppConfigFile('''false''');        ==>  '/home/user/.config/MyProg.cfg'
 +
  GetAppConfigFile('''false, true''');  ==>  '/home/user/.config/MyProg/MyProg.cfg'
 +
 
 +
Sie werden bemerken, dass globale Konfigurationseinstellungen im Verzeichnis /etc gespeichert werden und lokale Konfigurationseinstellungen in einem verborgenen Ordner im Home-Verzeichnis des Benutzers (Verzeichnise, deren Namen mit einem Punkt beginnen, sind in unter Linux versteckte Verzeichnisse). Sie können ein Verzeichnis an dem Ort erstellen, der von GetAppConfigDir geliefert wird, und die Konfigurationbsdateien dort ablegen.
 +
 
 +
Anmerkung: Normalen Benutzern ist es nicht erlaubt in das /etc Verzeichnis zu schreiben. Nur Benutzer mit Administratorrechten dürfen das.
 +
 
 +
Das folgende Beispiel illustriert die Ausgabe dieser Funktionen auf verschiedenen Systemen:
 +
 
 +
<syntaxhighlight lang="pascal">
 
program project1;
 
program project1;
  
Line 74: Line 99:
 
   WriteLn(GetAppConfigFile(False));
 
   WriteLn(GetAppConfigFile(False));
 
end.
 
end.
</pre>
+
</syntaxhighlight>
  
The output on a GNU/Linux system:
+
* Die Ausgabe unter Windows XP:
 
 
<pre>
 
/etc
 
/home/felipe/project1
 
/etc/project1.cfg
 
/home/felipe/.project1
 
</pre>
 
 
 
You can notice that glocal configuration files are stored on the /etc directory and local configurations are stored on a hidden folder on the user's home directory. Directories whose name begin with a dot (.) are hidden on Linux. You can create a directory on the location returned by GetAppConfigDir and then store configuration files there.
 
 
 
The output on Windows XP:
 
  
 
<pre>
 
<pre>
Line 96: Line 110:
 
</pre>
 
</pre>
  
Notice that the function uses the directory where the application is to store global configurations on Windows.
+
Es ist zu beachten, dass die Funktion das Verzeichnis für globale Anwendungsdaten unter Windows verwendet.
  
Note: The use of UPX interferes with the use of the GetAppConfigDir and GetAppConfigFile functions.
+
Anmerkung: Die Verwendung von UPX stört die Verwendung von GetAppConfigDir und GetAppConfigFile Funktionen.
  
==Making do without Windows COM Automation==
+
=== Storing data files für ihre Anwendungen ===
 +
 
 +
Eine sehr häufige Frage ist, wo man Datendateien speichern soll, die eine Anwendung benötigen könnte wie Musik, Bilder, Datenbanken und andere. Dieser Abschnitt bietet eine besondere Lösung, bei der die Datendateien im selben Verzeichnis wie das executable gespeichert werden (oder jedem anderen darauf basierenden Verzeichnis, wie MyDirectory + 'data' + PathDelim + 'myfile.dat'), und unter Unix-Systemen wird es in einem Verzeichnis sein, das aus einer Konfigurationsdatei gelesen wurde. Wenn keine Konfigurationsdatei existiert oder diese keine Info enthält, dann wird eine Konstante ('/usr/share/myapp/') genutzt als Vorgabeverzeichnis.
 +
 
 +
Der Konfigurationsdateipfad wird mit der GetAppConfigFile Funktion aus der Laufzeitbibliothek gefunden.
 +
 
 +
Unterhalb ist eine vollständige Unit, die sie für ihre Anwendungen verwenden können.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
unit appsettings;
 +
 
 +
interface
 +
 
 +
{$ifdef fpc}
 +
  {$mode delphi}{$H+}
 +
{$endif}
 +
 
 +
uses
 +
{$IFDEF Win32}
 +
  Windows,
 +
{$ENDIF}
 +
  Classes, SysUtils, Forms, IniFiles;
 +
 
 +
type
 +
 
 +
{ TConfigurations }
 +
 
 +
TConfigurations = class(TObject)
 +
private
 +
  ConfigFilePath: string;
 +
public
 +
  {other settings as fields here}
 +
  MyDirectory: string;
 +
  constructor Create;
 +
  destructor Destroy; override;
 +
  procedure ReadFromFile(Sender: TObject);
 +
  procedure Save(Sender: TObject);
 +
end;
 +
 
 +
 
 +
var
 +
vConfigurations: TConfigurations;
 +
 
 +
implementation
 +
 
 +
const
 +
  DefaultDirectory = '/usr/share/myapp/';
 +
 
 +
  SectionGeneral  = 'General';
 +
  SectionUnix      = 'UNIX';
 +
 
 +
  IdentMyDirectory = 'MyDirectory';
 +
 
 +
{ TConfigurations }
 +
 
 +
constructor TConfigurations.Create;
 +
begin
 +
{$ifdef win32}
 +
ConfigFilePath := ExtractFilePath(Application.EXEName) + 'myapp.ini';
 +
{$endif}
 +
{$ifdef Unix}
 +
ConfigFilePath := GetAppConfigFile(False) + '.conf';
 +
{$endif}
 +
 
 +
ReadFromFile(nil);
 +
end;
 +
 
 +
destructor TConfigurations.Destroy;
 +
begin
 +
Save(nil);
 +
 
 +
inherited Destroy;
 +
end;
 +
 
 +
procedure TConfigurations.Save(Sender: TObject);
 +
var
 +
MyFile: TIniFile;
 +
begin
 +
MyFile := TIniFile.Create(ConfigFilePath);
 +
try
 +
  MyFile.WriteString(SectionUnix, IdentMyDirectory, MyDirectory);
 +
finally
 +
  MyFile.Free;
 +
end;
 +
end;
 +
 
 +
procedure TConfigurations.ReadFromFile(Sender: TObject);
 +
var
 +
MyFile: TIniFile;
 +
begin
 +
MyFile := TIniFile.Create(ConfigFilePath);
 +
try
 +
{$ifdef Win32}
 +
  MyDirectory := MyFile.ReadString(SectionUnix, IdentMyDirectory,
 +
ExtractFilePath(Application.EXEName));
 +
{$else}
 +
  MyDirectory := MyFile.ReadString(SectionUnix, IdentMyDirectory,
 +
DefaultDirectory);
 +
{$endif}
 +
finally
 +
  MyFile.Free;
 +
end;
 +
end;
 +
 
 +
initialization
 +
 
 +
vConfigurations := TConfigurations.Create;
 +
 
 +
finalization
 +
 
 +
FreeAndNil(vConfigurations);
 +
 
 +
end.
 +
</syntaxhighlight>
 +
 
 +
und hier ein Beispielcode, wie man diese Unit verwendet:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
  bmp := TBitmap.Create
 +
  try
 +
    bmp.LoadFromFile(vConfigurations.MyDirectory + 'MyBitmap.bmp');
 +
  finally
 +
    bmp.Free;
 +
  end;
 +
</syntaxhighlight>
 +
 
 +
== Making do without Windows COM Automation ==
  
 
With Windows, Automation is a powerful way not only of manipulating other programs remotely but also for allowing other programs to manipulate your program. With Delphi you can make your program both an Automation client and an Automation server, meaning it can both manipulate other programs and in turn be manipulated by other programs.
 
With Windows, Automation is a powerful way not only of manipulating other programs remotely but also for allowing other programs to manipulate your program. With Delphi you can make your program both an Automation client and an Automation server, meaning it can both manipulate other programs and in turn be manipulated by other programs.
  
Unfortunately, Automation isn't available on OS X and Linux. However, you can simulate some of the functionality of Automation on OS X using AppleScript.
+
Leider ist Automation nicht verfügbar unter OS X und Linux. Jedoch können sie einen Teil der Funktionalität von Automation unter OS X simulieren unter Verwendung von AppleScript.
  
AppleScript is similar to Automation in some ways. For example, you can write scripts that manipulate other programs. Here's a very simple example of AppleScript that starts NeoOffice (the Mac version of OpenOffice.org):
+
AppleScript ist ähnlich wie Automation in mancher Hinsicht. Zum Beispiel, sie können Skripte schreiben, die andere Programme manipulieren. Hier ist ein sehr einfaches Beispiel von AppleScript, das NeoOffice startet (die Mac Version von OpenOffice.org):
  
 
   tell application "NeoOffice"
 
   tell application "NeoOffice"
Line 112: Line 252:
 
   end tell
 
   end tell
  
An app that is designed to be manipulated by AppleScript provides a "dictionary" of classes and commands that can be used with the app, similar to the classes of a Windows Automation server. However, even apps like NeoOffice that don't provide a dictionary will still respond to the commands "launch", "activate" and "quit". AppleScript can be run from the OS X Script Editor or Finder or even converted to an app that you can drop on the dock just like any app. You can also run AppleScript from your program, as in this example:
+
Eine Anwendung, die is designed to be manipulated by AppleScript provides a "dictionary" of classes and commands that can be used with the app, similar to the classes of a Windows Automation server. However, even apps like NeoOffice that don't provide a dictionary will still respond to the commands "launch", "activate" and "quit". AppleScript can be run from the OS X Script Editor or Finder or even converted to an app that you can drop on the dock just like any app. You can also run AppleScript from your program, as in this example:
  
 +
<syntaxhighlight lang="pascal">
 
   Shell('myscript.applescript');
 
   Shell('myscript.applescript');
 +
</syntaxhighlight>
  
This assumes the script is in the indicated file. You can also run scripts on the fly from your app using the OS X OsaScript command:
+
Dies setzt voraus, dass das Skript in der angegebenen Datei ist. You can also run scripts on the fly from your app using the OS X OsaScript command:
  
 +
<syntaxhighlight lang="pascal">
 
   Shell('osascript -e '#39'tell application "NeoOffice"'#39 +
 
   Shell('osascript -e '#39'tell application "NeoOffice"'#39 +
 
         ' -e '#39'launch'#39' -e '#39'end tell'#39);
 
         ' -e '#39'launch'#39' -e '#39'end tell'#39);
 
         {Note use of #39 to single-quote the parameters}
 
         {Note use of #39 to single-quote the parameters}
 +
</syntaxhighlight>
  
 
However, these examples are just the equivalent of the following Open command:
 
However, these examples are just the equivalent of the following Open command:
  
 +
<syntaxhighlight lang="pascal">
 
   Shell('open -a NeoOffice');
 
   Shell('open -a NeoOffice');
 +
</syntaxhighlight>
  
The real power of AppleScript is to manipulate programs remotely to create and open documents and automate other activities. How much you can do with a program depends on how extensive its AppleScript dictionary is (if it has one). For example, Microsoft's Office X programs are not very useable with AppleScript, whereas the newer Office 2004 programs have completely rewritten AppleScript dictionaries that compare in many ways with what's available via the Windows Office Automation servers.
+
Die wirkliche Stärke von AppleScript is to manipulate programs remotely to create and open documents and automate other activities. How much you can do with a program depends on how extensive its AppleScript dictionary is (if it has one). For example, Microsoft's Office X programs are not very useable with AppleScript, whereas the newer Office 2004 programs have completely rewritten AppleScript dictionaries that compare in many ways with what's available via the Windows Office Automation servers.
  
 
While Linux shells support sophisticated command line scripting, the type of scripting is limited to what can be passed to a program on the command line. No access to a program's internal classes and commands are available with Linux the way they are via Windows Automation and OS X AppleScript.
 
While Linux shells support sophisticated command line scripting, the type of scripting is limited to what can be passed to a program on the command line. No access to a program's internal classes and commands are available with Linux the way they are via Windows Automation and OS X AppleScript.
Line 132: Line 278:
 
As with Windows, many OS X and Linux programs are made up of multiple library files (.dylib and .so extensions). Sometimes these libraries are designed so you can also use them in programs you write. While this can be a way of adding some of the functionality of an external program to your program, it's not really the same as running and manipulating the external program itself. Instead, your program is just linking to and using the external program's library similar to the way it would use any programming library.
 
As with Windows, many OS X and Linux programs are made up of multiple library files (.dylib and .so extensions). Sometimes these libraries are designed so you can also use them in programs you write. While this can be a way of adding some of the functionality of an external program to your program, it's not really the same as running and manipulating the external program itself. Instead, your program is just linking to and using the external program's library similar to the way it would use any programming library.
  
==Weiterführende Links==
+
== Arbeiten mit Dateien und Ordnern ==
 +
 
 +
Wenn sie mit Dateien und Ordnern arbeiten ist es wichtig, nicht-plattformspezifische Pfadbegrenzungszeichen und Zeilenendsequenzen zu verwenden. Hier ist eine Liste der deklarierten Konstanten in Lazarus, die bei der Arbeit mit Dateien und Ordnern verwendet werden sollten.
 +
 
 +
* '''PathSep''', '''PathSeparator''': path separator when adding many paths together (';', ...)
 +
* '''PathDelim''', '''DirectorySeparator''': directory separator for each platform ('/', '\', ...)
 +
* '''LineEnding''': proper line ending character sequence (#13#10 - CRLF, #10 - LF, ...)
 +
 
 +
== Weiterführende Links ==
  
 
* http://www.midnightbeach.com/jon/pubs/Kylix.html - Ein Führer für Windows-Programmierer, die mit Kylix beginnen möchten. Viele Konzepte und Code Beispiele gelten auch für Lazarus.
 
* http://www.midnightbeach.com/jon/pubs/Kylix.html - Ein Führer für Windows-Programmierer, die mit Kylix beginnen möchten. Viele Konzepte und Code Beispiele gelten auch für Lazarus.
 +
* http://www.stack.nl/~marcov/porting.pdf Ein Handbuch für das Schreiben von portablem Quellcode, hauptsächlich zwischen verschiedenen Compilern.
 +
<br>
 +
<br>
 +
[[Category:Tutorials/de]]{{AutoCategory}}

Latest revision as of 18:42, 27 February 2018

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) polski (pl) русский (ru) 中文(中国大陆)‎ (zh_CN)

Zurück zu den Zusätzlichen Informationen.

Diese Seite ist der Beginn einer Einführung die das Hauptaugenmerk auf die Erstellung von Multiplattformanwendungen mit Lazarus richtet. Es werden die notwendigen Vorkehrungen, ein Programm portabel zu halten und auch der Portierungsprozess eines bereits bestehenden Programms betrachtet. Ich lade den Leser dazu ein, diesen Artikel zu erweitern.


Einführung in die Multiplattform Programmierung

Welche Betriebssysteme sollen unterstützt werden?

Um diese Frage zu beantworten, müssen sie ermitteln, wer ihre potentiellen Nutzer sind und wie ihr Programm genutzt werden soll. Die Antwort auf diese Frage hängt davon ab, wo sie ihre Programm einsetzen möchten.

Zum Beispiel Europa: Wenn sie eine Desktop-Anwendung entwickeln, können sie entscheiden, dass es nur für Windows und OS X Sinn macht. OS X ist das populärste Unix der Welt und strömt auf Desktops, wohingegen Linux meist dort heraus gezögert wird. Bedenken sie die 100:10:1 Regel, die besagt, dass in jeder größeren Organisation oder Benutzergruppe es nicht ungewöhnlich ist, Windows, OS X und Linux Arbeitsplätze in eben jener Aufteilung zu finden.

An anderen Orten wie beispielsweise Südamerika ist Windows größtenteils marktbeherrschend, wohingegen Linux als Dekstop Plattform aufstrebt und in einigen großen Marktketten fast gleich mit Windows verkauft wird. OS X wird hauptsächlich im Audio- und Videobereich eingesetzt.

Ist die Hand voll OS X und Linux Nutzer den extra Portierungsaufwand wert, der zum Entwickeln, Packen, Verteilen und Supporten benötigt ist? Ein klares ja, wenn es das Projekt es verlangt. Oder wenn der mehr benötigte Aufwand gering ist, wird die Antwort ebenso wahrscheinlich ja sein. Wenn sie sie aus Prinzip unterstützen, wird die Antwort auch ja sein, solange der extra Aufwand nicht als Hinderungsgrund zur Fertigstellung des Projektes steht.

Wenn sie Software entwickeln, die auf einem Webserver laufen soll, ist die am meisten genutzte Plattform Unix. In diesem Fall ist es sinnvoll, Linux, Solaris, *BSD und andere Unix-Derivate als Zielplattform anzusehen, wobei zum Teil auch Windows Server zum Einsatz kommen.

Wenn sie nur für eine Plattform entwickeln, werden vielleicht Free Pascal und Lazarus nicht die besten Mittel dafür sein, es sei denn, sie möchten sich die Möglichkeit offen halten, spätere Versionen ihrer Software auf andere Plattformen zu portieren. Wenn sie beispielsweise nur Windows Desktopanwendungen erstellen, könnte Delphi die bessere Alternative sein.

Sobald sie die Plattformunabhängigkeit gemeistert haben, können Sie sich normalerweise auf das Problem konzentrieren, für das die Software entworfen werden soll und die Hauptzeit der Entwicklung auf der Plattform verbringen, über die sie verfügen oder auf der sie sich am wohlsten fühlen. Sie können, sobald Sie die Fallstricke der Plattformunabhängigkeit in Ihrem Design erkannt haben, größtenteils die anderen Plattformen ignorieren, ebenso, als wenn sie für eine einzelne Plattform entwickeln würden.

Jedoch kommen sie an einen Punkt, an dem sie die Verteilung und die Ausführung ihres Programms auf den anderen Plattformen testen müssen. Spätestens dann ist es hilfreich, unbegrenzten Zugriff auf Rechner mit ihren gewählten Zielplattformen zu haben.

Wenn Sie nicht mehrere PC's haben möchten, können Sie ein Dual-Boot System mit Windows und Linux konfigurieren oder Windows und Linux auf ihrem Mac in einem Emulator wie Virtual PC oder iEmulator laufen lassen.

Der Portierungsvorgang zwischen Windows und Linux

Windows API Funktionen

Viele Windows Programme nutzen extensiv die Windows API. In plattformübergreifenden Anwendungen können diese Funktionen nicht direkt benutzt werden, sondern müssen in eine Kompilerdirektive eingeschlossen werden, z.B. {$IFDEF Win32}.

Glücklicherweise werden die meist genutzten Windows API Funktionen zur Verwendung in der Unit LCLIntf implementiert. Diese Unit kann die Lösung für Programme sein, die sehr stark die Windows API verwenden, obwohl die beste Lösung der Austausch dieser Aufrufe durch plattformübergreifende Komponenten der LCL ist. Sie können beispielsweise alle Aufrufe von GDI Zeichenfunktionen durch das TCanvas Objekt ersetzen.

Dateisystemunterschiede

Einer besonderen Beobachtung für die Portierung von Applikationen zwischen Linux und Windows bedarf das Dateisystem. Unter Windows sind Dateinamen beispielsweise nicht case-sensitiv, wohingegen sie es unter Unix-Plattformen sind. Dies kann der Grund für eine Menge nervenraubender Fehler sein. Daher sollte jede portable Anwendung konsistente Dateinamen verwenden.

Unix kennt kein "Programmverzeichnis"

Eine Sorge, wenn man Anwendungen zwischen Linux und Windows portiert, ist das Dateisystem. Viele Programmierer sind gewöhnt, ExtractFilePath(ParamStr(0)) oder Application.ExeName aufzurufen um den Ort der ausführbaren Datei zu erhalten, und dann nach den notwendigen Dateien für die Programmausführung (Bilder, XML Dateien, Datenbankdateien, etc) zu suchen basierend auf dem Ort der ausführbaren Datei. Das ist falsch unter Linux. Die Zeichenkette bei ParamStr(0) kann nicht nur das Verzeichnis des executable enthalten, ebenso variiert es zwischen verschiedenen Shell-Programmen (sh, bash, etc).

Sogar wenn Application.ExeName tatsächlich wüsste, wo die ausgeführte Datei sich befindet, könnte es sich immer noch um einen symbolischen Link handeln und nur das Verzeichnis des Links würde verwendet werden.

Was kann man also machen? Unter Linux sollten Sie zwei verschiedene Orte verwenden, um Konfigurations- und Ressourcen-Dateien zu speichern:

  • Ressourcendateien (z.B. Bilder, Hilfedateien)

Ein festgelegtes, bevorzugtes Verzeichnis für ausführbare und Ressourcendateien, das unveränderlich ist.

Das kann zum Beispiel sein: /usr/share/app_name oder /opt/app_name

Die meisten Programme werden ohne Administrator/Root-Rechte ausgeführt werden und nur Administrator/Root wird die Schreibrechte an dem für ein bestimmtes Programm definierten Verzeichnis besitzen. Schreiben Sie daher keine Daten in das Verzeichnis, sondern greifen Sie nur lesend darauf zu.

  • Konfigurationsdateien

Sie können die Funktion GetAppConfigDir aus der Unit SysUtils verwenden, um einen geeigneten Ort zur Ablage der Konfigurationsdateien auf verschiedenen Systemen zu ermitteln. Diese Funktion besitzt den boolschen Parameter Global. Wenn dieser true ist, dann ist das zurückgegebene Verzeichnis ein "globales Verzeichnis", d.h. es betrifft alle Benutzer auf dem System. Wenn der Parameter Global false ist, dann ist das Verzeichnis spezifisch für den Benutzer, der es ausführt. Auf Systemen, die Mehrbenutzer-Umgebungen nicht unterstützen, kann es sich um ein und dasselbe Verzeichnis handeln.

Es gibt auch GetAppConfigFile, das einen geeigneten Namen für eine Anwendungs-Konfigurationsdatei zurückgibt. Diese Funktion benutzt denselben Parameter Global wie GetAppConfigDir. Zusätzlich kann dort der optionale Parameter SubDir verwendet werden, der ans Ende der Verzeichniskette ein eigenes Unterverzeichnis anfügt (SubDir ist per Voreinstellung False, d.h. GetAppConfigFile(true) ist dasselbe wie GetAppConfigFile(true, false).

Auf einem GNU/Linux-System ergeben die Aufrufe von GetAppConfigDir und GetAppConfigFile folgende Resultate:

 program MyProg;
 (...)
 
 GetAppConfigDir(true);           ==>   '/etc/MyProg/'
 GetAppConfigFile(true);          ==>   '/etc/MyProg.cfg'
 GetAppConfigFile(true, true);    ==>   '/etc/MyProg/MyProg.cfg'
 
 GetAppConfigDir(false);          ==>   '/home/user/.config/MyProg/'
 GetAppConfigFile(false);         ==>   '/home/user/.config/MyProg.cfg'
 GetAppConfigFile(false, true);   ==>   '/home/user/.config/MyProg/MyProg.cfg'

Sie werden bemerken, dass globale Konfigurationseinstellungen im Verzeichnis /etc gespeichert werden und lokale Konfigurationseinstellungen in einem verborgenen Ordner im Home-Verzeichnis des Benutzers (Verzeichnise, deren Namen mit einem Punkt beginnen, sind in unter Linux versteckte Verzeichnisse). Sie können ein Verzeichnis an dem Ort erstellen, der von GetAppConfigDir geliefert wird, und die Konfigurationbsdateien dort ablegen.

Anmerkung: Normalen Benutzern ist es nicht erlaubt in das /etc Verzeichnis zu schreiben. Nur Benutzer mit Administratorrechten dürfen das.

Das folgende Beispiel illustriert die Ausgabe dieser Funktionen auf verschiedenen Systemen:

program project1;

{$mode objfpc}{$H+}

uses
  SysUtils;

begin
  WriteLn(GetAppConfigDir(True));
  WriteLn(GetAppConfigDir(False));
  WriteLn(GetAppConfigFile(True));
  WriteLn(GetAppConfigFile(False));
end.
  • Die Ausgabe unter Windows XP:
C:\Programas\teste
C:\Documents and Settings\felipe\Configurações Locais\Dados de aplicativos\project2
C:\Programas\teste\project2.cfg
C:\Documents and Settings\felipe\Configurações Locais\Dados de aplicativos\project2\project2.cfg

Es ist zu beachten, dass die Funktion das Verzeichnis für globale Anwendungsdaten unter Windows verwendet.

Anmerkung: Die Verwendung von UPX stört die Verwendung von GetAppConfigDir und GetAppConfigFile Funktionen.

Storing data files für ihre Anwendungen

Eine sehr häufige Frage ist, wo man Datendateien speichern soll, die eine Anwendung benötigen könnte wie Musik, Bilder, Datenbanken und andere. Dieser Abschnitt bietet eine besondere Lösung, bei der die Datendateien im selben Verzeichnis wie das executable gespeichert werden (oder jedem anderen darauf basierenden Verzeichnis, wie MyDirectory + 'data' + PathDelim + 'myfile.dat'), und unter Unix-Systemen wird es in einem Verzeichnis sein, das aus einer Konfigurationsdatei gelesen wurde. Wenn keine Konfigurationsdatei existiert oder diese keine Info enthält, dann wird eine Konstante ('/usr/share/myapp/') genutzt als Vorgabeverzeichnis.

Der Konfigurationsdateipfad wird mit der GetAppConfigFile Funktion aus der Laufzeitbibliothek gefunden.

Unterhalb ist eine vollständige Unit, die sie für ihre Anwendungen verwenden können.

unit appsettings;

interface

{$ifdef fpc}
  {$mode delphi}{$H+}
{$endif}

uses
{$IFDEF Win32}
  Windows,
{$ENDIF}
  Classes, SysUtils, Forms, IniFiles;

type

 { TConfigurations }

 TConfigurations = class(TObject)
 private
   ConfigFilePath: string;
 public
   {other settings as fields here}
   MyDirectory: string;
   constructor Create;
   destructor Destroy; override;
   procedure ReadFromFile(Sender: TObject);
   procedure Save(Sender: TObject);
 end;


var
 vConfigurations: TConfigurations;

implementation

const
  DefaultDirectory = '/usr/share/myapp/';

  SectionGeneral   = 'General';
  SectionUnix      = 'UNIX';

  IdentMyDirectory = 'MyDirectory';

{ TConfigurations }

constructor TConfigurations.Create;
begin
{$ifdef win32}
 ConfigFilePath := ExtractFilePath(Application.EXEName) + 'myapp.ini';
{$endif}
{$ifdef Unix}
 ConfigFilePath := GetAppConfigFile(False) + '.conf';
{$endif}

 ReadFromFile(nil);
end;

destructor TConfigurations.Destroy;
begin
 Save(nil);

 inherited Destroy;
end;

procedure TConfigurations.Save(Sender: TObject);
var
 MyFile: TIniFile;
begin
 MyFile := TIniFile.Create(ConfigFilePath);
 try
   MyFile.WriteString(SectionUnix, IdentMyDirectory, MyDirectory);
 finally
   MyFile.Free;
 end;
end;

procedure TConfigurations.ReadFromFile(Sender: TObject);
var
 MyFile: TIniFile;
begin
 MyFile := TIniFile.Create(ConfigFilePath);
 try
{$ifdef Win32}
   MyDirectory := MyFile.ReadString(SectionUnix, IdentMyDirectory,
ExtractFilePath(Application.EXEName));
{$else}
   MyDirectory := MyFile.ReadString(SectionUnix, IdentMyDirectory,
DefaultDirectory);
{$endif}
 finally
   MyFile.Free;
 end;
end;

initialization

 vConfigurations := TConfigurations.Create;

finalization

 FreeAndNil(vConfigurations);

end.

und hier ein Beispielcode, wie man diese Unit verwendet:

  bmp := TBitmap.Create
  try
    bmp.LoadFromFile(vConfigurations.MyDirectory + 'MyBitmap.bmp');
  finally
    bmp.Free;
  end;

Making do without Windows COM Automation

With Windows, Automation is a powerful way not only of manipulating other programs remotely but also for allowing other programs to manipulate your program. With Delphi you can make your program both an Automation client and an Automation server, meaning it can both manipulate other programs and in turn be manipulated by other programs.

Leider ist Automation nicht verfügbar unter OS X und Linux. Jedoch können sie einen Teil der Funktionalität von Automation unter OS X simulieren unter Verwendung von AppleScript.

AppleScript ist ähnlich wie Automation in mancher Hinsicht. Zum Beispiel, sie können Skripte schreiben, die andere Programme manipulieren. Hier ist ein sehr einfaches Beispiel von AppleScript, das NeoOffice startet (die Mac Version von OpenOffice.org):

 tell application "NeoOffice"
   launch
 end tell

Eine Anwendung, die is designed to be manipulated by AppleScript provides a "dictionary" of classes and commands that can be used with the app, similar to the classes of a Windows Automation server. However, even apps like NeoOffice that don't provide a dictionary will still respond to the commands "launch", "activate" and "quit". AppleScript can be run from the OS X Script Editor or Finder or even converted to an app that you can drop on the dock just like any app. You can also run AppleScript from your program, as in this example:

  Shell('myscript.applescript');

Dies setzt voraus, dass das Skript in der angegebenen Datei ist. You can also run scripts on the fly from your app using the OS X OsaScript command:

  Shell('osascript -e '#39'tell application "NeoOffice"'#39 +
        ' -e '#39'launch'#39' -e '#39'end tell'#39);
        {Note use of #39 to single-quote the parameters}

However, these examples are just the equivalent of the following Open command:

  Shell('open -a NeoOffice');

Die wirkliche Stärke von AppleScript is to manipulate programs remotely to create and open documents and automate other activities. How much you can do with a program depends on how extensive its AppleScript dictionary is (if it has one). For example, Microsoft's Office X programs are not very useable with AppleScript, whereas the newer Office 2004 programs have completely rewritten AppleScript dictionaries that compare in many ways with what's available via the Windows Office Automation servers.

While Linux shells support sophisticated command line scripting, the type of scripting is limited to what can be passed to a program on the command line. No access to a program's internal classes and commands are available with Linux the way they are via Windows Automation and OS X AppleScript.

As with Windows, many OS X and Linux programs are made up of multiple library files (.dylib and .so extensions). Sometimes these libraries are designed so you can also use them in programs you write. While this can be a way of adding some of the functionality of an external program to your program, it's not really the same as running and manipulating the external program itself. Instead, your program is just linking to and using the external program's library similar to the way it would use any programming library.

Arbeiten mit Dateien und Ordnern

Wenn sie mit Dateien und Ordnern arbeiten ist es wichtig, nicht-plattformspezifische Pfadbegrenzungszeichen und Zeilenendsequenzen zu verwenden. Hier ist eine Liste der deklarierten Konstanten in Lazarus, die bei der Arbeit mit Dateien und Ordnern verwendet werden sollten.

  • PathSep, PathSeparator: path separator when adding many paths together (';', ...)
  • PathDelim, DirectorySeparator: directory separator for each platform ('/', '\', ...)
  • LineEnding: proper line ending character sequence (#13#10 - CRLF, #10 - LF, ...)

Weiterführende Links