Difference between revisions of "Multiplatform Programming Guide/pl"

From Lazarus wiki
Jump to navigationJump to search
(Kopia wersji en)
 
(→‎External links: tłumaczenie na j. polski)
 
(22 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
{{Multiplatform Programming Guide}}
 
{{Multiplatform Programming Guide}}
 +
<div style="font-size:1.88em;margin:0.75em 0;">Przewodnik programowania wieloplatformowego</div>
  
This is a tutorial on writing cross-platform applications with Lazarus and Free Pascal. It will cover the necessary precautions to aid in creating a cross-platform ready program that is ready to [[Deploying Your Application|deploy]].
+
To jest samouczek dotyczący pisania aplikacji wieloplatformowych z Lazarusem i Free Pascalem. Obejmuje niezbędne środki ostrożności, aby pomóc w stworzeniu wieloplatformowego programu gotowego do [[Deploying Your Application|wdrożenia]].
  
Most [[LCL]] applications work in a cross-platform way without any extra effort.
+
Większość aplikacji LCL działa na wielu platformach bez dodatkowej pracy.
This principle is called [[Write once compile anywhere|„write once, compile anywhere“]].
+
Ta zasada nazywa się [[Write once compile anywhere/pl|„napisz raz, kompiluj wszędzie”]].
  
== Introduction to Multiplatform (Cross-platform) Programming ==
+
== Wprowadzenie do programowania wieloplatformowego (międzyplatformowego) ==
  
=== How many platforms do you need? ===
+
=== Ile platform potrzebujesz? ===
  
To answer this question, you should first determine who your potential users are and how your program will be used. This question depends on where you are deploying your application.
+
Aby odpowiedzieć na to pytanie, powinieneś najpierw określić, kim są Twoi potencjalni użytkownicy i jak Twój program będzie używany. To pytanie zależy od tego, gdzie wdrażasz swoją aplikację.
  
If you are developing generic desktop software in 2014, Microsoft Windows may be the most important platform. Note that macOS and/or Linux are gaining in popularity, and may be a significant target for your application.
+
Jeśli tworzysz ogólne oprogramowanie komputerowe w 2014 roku, Microsoft Windows może być najważniejszą platformą. Pamiętaj, że macOS i/lub Linux zyskują na popularności i mogą być ważnym celem dla Twojej aplikacji.
  
The popularity of the various desktop operating systems differs by country, by the type of software used, and with the target audience; there's no general rule. For example, macOS is quite popular in North America and western Europe, while in South America macOS is mostly restricted to video and sound work.
+
Popularność różnych systemów operacyjnych na komputery stacjonarne różni się w zależności od kraju, rodzaju używanego oprogramowania i grupy docelowej; nie ma ogólnej zasady. Na przykład macOS jest dość popularny w Ameryce Północnej i Europie Zachodniej, podczas gdy w Ameryce Południowej macOS ogranicza się głównie do pracy z wideo i dźwiękiem.
  
On many contract projects, only one platform is relevant. Free Pascal and Lazarus are quite capable of writing software targeted at a specific platform. You can, for example, access the full Windows API to write a well integrated Windows program.
+
W wielu projektach kontraktowych odpowiednia jest tylko jedna platforma. Free Pascal i Lazarus są w stanie pisać oprogramowanie ukierunkowane na konkretną platformę. Możesz na przykład uzyskać dostęp do pełnego interfejsu API Windows, aby napisać dobrze zintegrowany program Windows.
  
If you're developing software that will run on a web server, a Unix platform in one of its various flavors is commonly used. In this case, perhaps only Linux, Solaris, *BSD and other Unixes make sense as your target platforms, although you may want to add support for Windows for completeness.
+
Jeśli tworzysz oprogramowanie, które będzie działać na serwerze sieciowym, powszechnie używana jest platforma uniksowa w jednym z jej różnych wariantów. Być może w tym przypadku jako platformy docelowe sens mają tylko Linux, Solaris, *BSD i inne Uniksy, chociaż możesz chcieć dodać do kompletu obsługę Windows.
  
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. For that, it will be helpful to have unrestricted access to machines running the target operating systems. If you don't want multiple physical computers, investigate dual-booting or Virtual Machine (VM) solutions like:
+
Po rozwiązaniu wszelkich problemów międzyplatformowych w swoim projekcie, możesz w dużej mierze zignorować inne platformy, podobnie jak w przypadku programowania dla jednej platformy. Jednak w pewnym momencie będziesz musiał przetestować wdrażanie i uruchamianie programu na innych platformach. W tym celu pomocny będzie nieograniczony dostęp do maszyn z docelowymi systemami operacyjnymi. Jeśli nie chcesz mieć wielu fizycznych komputerów, sprawdź rozwiązania z podwójnym rozruchem lub maszyną wirtualną (VM), taką jak:
  
* [https://www.vmware.com/products/fusion.html VMware Fusion for Mac] - Host system must be running Intel macOS (Commercial/Free for non-commercial use).
+
* [https://www.vmware.com/products/fusion.html VMware Fusion for Mac] - Systemie hosta, na którym musi być uruchomiony system Intel macOS (komercyjny/bezpłatny do użytku niekomercyjnego).
* [https://www.vmware.com/products/workstation-player.html VMware Workstation Player] - Host system running Windows 64 bit or Linux 64 bit (Commercial/Free for personal use).
+
* [https://www.vmware.com/products/workstation-player.html VMware Workstation Player] - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjny/bezpłatny do użytku osobistego).
* [https://www.vmware.com/products/workstation-pro.html VMware Workstation Pro] - Host system running Windows 64 bit or Linux 64 bit  (Commercial/Free trial).
+
* [https://www.vmware.com/products/workstation-pro.html VMware Workstation Pro] - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjna/bezpłatna wersja próbna).
* [https://www.parallels.com/ Parallels Desktop for Mac] - Host system must be running Intel macOS (Commercial/Free trial). Note: There is a [https://b2b.parallels.com/Apple-Silicon Technical Preview] that will run on Apple M1 ARM64 processors which will run the ARM versions of Linux and [https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64 Windows 10 Insider Preview].
+
* [https://www.parallels.com/ Parallels Desktop for Mac] - Na systemie hosta musi być uruchomiony system Intel macOS (komercyjna/bezpłatna wersja próbna). Uwaga: istnieje [https://b2b.parallels.com/Apple-Silicon Podgląd Techniczny], który będzie działał na procesorach Apple M1 ARM64, i który będzie obsługiwał wersje ARM systemu Linux i [https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64 Windows 10 Insider Preview].
* [https://www.virtualbox.org/ VirtualBox] - Host system can be running Intel macOS, Windows, Linux or Solaris (Open Source).
+
* [https://www.virtualbox.org/ VirtualBox] - Na systemie hosta może działać Intel macOS, Windows, Linux lub Solaris (Open Source).
  
Some, eg Parallels on the Mac, make it trivial to install a desktop Linux operating system with a single click.
+
Niektóre z nich, np. Parallels na Macu, sprawiają, że instalacja stacjonarnego systemu operacyjnego Linux za pomocą jednego kliknięcia jest banalna.
  
'''See also:''' [[Small Virtual Machines]] and [[Qemu and other emulators]].
+
'''Zobacz także:''' [[Small Virtual Machines|Małe maszyny wirtualne]] i [[Qemu and other emulators|Qemu i inne emulatory]].
  
== Cross-platform Programming ==
+
== Programowanie międzyplatformowe ==
  
=== Working with files and folders ===
+
=== Praca z plikami i folderami ===
  
When working with files and folders, it is important to use non-platform specific path delimiters and [[End_of_Line|line ending]] sequences. Here is a list of declared [[Constant|constants]] in Lazarus to be used when working with files and folders.
+
Podczas pracy z plikami i folderami ważne jest, aby używać niespecyficznych dla platformy ograniczników ścieżki i sekwencji [[End_of_Line|końca wiersza]]. Oto lista zadeklarowanych [[Constant|stałych]] w Lazarusie, które powinny być używane podczas pracy z plikami i folderami.
  
* '''PathSep''', '''PathSeparator''': path separator when adding many paths together (';', ...)
+
* '''PathSep''', '''PathSeparator''': separator ścieżek używany podczas dodawania wielu ścieżek razem (';', ...)
* '''PathDelim''', '''DirectorySeparator''': directory separator for each platform ('/', '\', ...)
+
* '''PathDelim''', '''DirectorySeparator''': separator katalogów dla każdej platformy ('/', '\', ...)
* '''LineEnding''': proper line ending character sequence (#13#10 - CRLF, #10 - [[Line_feed|LF]], ...)
+
* '''LineEnding''': poprawna sekwencja znaków końca wiersza (#13#10 - CRLF, #10 - [[Line_feed|LF]], ...)
  
Another important thing to be noted is the case sensitiveness of the file system.
+
Inną ważną rzeczą, na którą należy zwrócić uwagę, jest rozróżnianie wielkości liter w systemie plików. W systemie Windows w nazwach plików zwykle nie jest rozróżniana wielkość liter, podczas gdy na platformach uniksowych (np. Linux, FreeBSD) zwykle rozróżniana jest wielkość liter, ale nie w macOS, pomimo jego dziedzictwa uniksowego. Należy jednak pamiętać, że jeśli system plików EXT2, EXT3 itp. jest zamontowany w systemie Windows, rozróżniana jest wielkość liter. Podobnie system plików FAT zamontowany w systemie Linux nie powinien rozróżniać wielkości liter.
On Windows filenames are usually not case sensitive, while they usually are case sensitive on Unix platforms (eg Linux, FreeBSD) but not macOS despite its Unix heritage. But note that if an EXT2, EXT3, etc file system is mounted on Windows, it would be case sensitive. Likewise, a FAT file system mounted on Linux should not be case sensitive.
 
  
Special attention should be paid to NTFS which is not case sensitive when used in Windows, but is case sensitive when mounted by POSIX OSes. This could cause '''various problems, including loss of files''' if files with the same filenames in different cases exist on an NTFS partition mounted in Windows. Using custom functions for checking and preventing creation of several files with the same names on NTFS should be considered by developers.
+
Szczególną uwagę należy zwrócić na NTFS, który nie rozróżnia wielkości liter, gdy jest używany w systemie Windows, ale rozróżnia wielkość liter, gdy jest montowany w systemach POSIX. Może to powodować '''różne problemy, w tym utratę plików''', jeśli pliki o tych samych nazwach, lecz różnych wariantach, istnieją na partycji NTFS zamontowanej w systemie Windows. Programiści powinni rozważyć użycie niestandardowych funkcji do sprawdzania i zapobiegania tworzenia kilku plików o tych samych nazwach w systemie NTFS.
  
macOS uses case insensitive filenames by default. This can be the cause of annoying bugs, so any portable application should use filenames consistently.
+
macOS domyślnie używa nazw plików bez uwzględniania wielkości liter. Może to być przyczyną irytujących błędów, więc każda przenośna aplikacja powinna konsekwentnie używać takich nazw plików.
  
The RTL file functions use the system encoding for file names. Under Windows this is one of the Windows code pages, while Linux, BSD and macOS usually use UTF-8. The unit '''FileUtil''' of the LCL provides file functions which takes UTF-8 strings like the rest of the LCL.
+
Funkcje plikowe biblioteki RTL używają kodowania systemowego dla nazw plików. W starszych systemach Windows (95/98/Me) jest to jedna ze stron kodowych systemu Windows, w nowszych UTF-16, podczas gdy Linux, BSD i macOS zwykle używają UTF-8. Moduł '''FileUtil''' biblioteki LCL zawiera funkcje plikowe, które przyjmują łańcuchy UTF-8, podobnie jak reszta LCL.
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// AnsiToUTF8 and UTF8ToAnsi need a widestring manager under Linux, BSD, macOS
+
// Funkcje AnsiToUTF8 i UTF8ToAnsi wymagają menedżera widestring pod Linuksem, BSD, macOS,
// but normally these OS use UTF-8 as system encoding so the widestringmanager
+
// ale zwykle te systemy operacyjne używają UTF-8 jako kodowania systemowego, więc widestringmanager
// is not needed.
+
// nie jest potrzebny.
 
function NeedRTLAnsi: boolean;// true if system encoding is not UTF-8
 
function NeedRTLAnsi: boolean;// true if system encoding is not UTF-8
 
procedure SetNeedRTLAnsi(NewValue: boolean);
 
procedure SetNeedRTLAnsi(NewValue: boolean);
function UTF8ToSys(const s: string): string;    // as UTF8ToAnsi but more independent of widestringmanager
+
function UTF8ToSys(const s: string): string;    // podobna do UTF8ToAnsi, ale nie jest już zależna od widestringmanager
function SysToUTF8(const s: string): string;    // as AnsiToUTF8 but more independent of widestringmanager
+
function SysToUTF8(const s: string): string;    // podobna do AnsiToUTF8, ale nie jest już zależna od widestringmanager
function UTF8ToConsole(const s: string): string; // converts UTF8 string to console encoding (used by Write, WriteLn)
+
function UTF8ToConsole(const s: string): string; // konwertuje ciąg znaków UTF8 na kodowanie konsoli (używane przez Write, WriteLn)
  
// file operations
+
// operacje na plikach
 
function FileExistsUTF8(const Filename: string): boolean;
 
function FileExistsUTF8(const Filename: string): boolean;
 
function FileAgeUTF8(const FileName: string): Longint;
 
function FileAgeUTF8(const FileName: string): Longint;
Line 84: Line 84:
 
function ForceDirectoriesUTF8(const Dir: string): Boolean;
 
function ForceDirectoriesUTF8(const Dir: string): Boolean;
  
// environment
+
// środowisko
 
function ParamStrUTF8(Param: Integer): string;
 
function ParamStrUTF8(Param: Integer): string;
 
function GetEnvironmentStringUTF8(Index: Integer): string;
 
function GetEnvironmentStringUTF8(Index: Integer): string;
Line 90: Line 90:
 
function GetAppConfigDirUTF8(Global: Boolean): string;
 
function GetAppConfigDirUTF8(Global: Boolean): string;
  
// other
+
// inne
 
function SysErrorMessageUTF8(ErrorCode: Integer): String;</syntaxhighlight>
 
function SysErrorMessageUTF8(ErrorCode: Integer): String;</syntaxhighlight>
  
===Empty file names and double path delimiters===
+
===Puste nazwy plików i podwójne separatory ścieżki===
  
There are differences in file/directory name handling in Windows versus Linux, Unix and Unix like systems.
+
Istnieją pewne różnice w obsłudze nazw plików/katalogów w systemie Windows w porównaniu z systemami Linux, Unix i Unix.
  
* Windows allows empty file names. That's why FileExistsUTF8('..\') checks under Windows in the parent directory for a file without name.
+
* Windows zezwala na puste nazwy plików. Dlatego FileExistsUTF8('..\') sprawdza w systemie Windows w katalogu nadrzędnym, czy istnieje plik bez nazwy.
* On Linux/Unix/Unix-like systems, an empty file is mapped to the directory and directories are treated as files. This means that FileExistsUTF8('../') under Unix checks for the existence of the parent directory, which normally results true.
+
* W systemach Linux/Unix/Uniksopodobnych do katalogu mapowany jest pusty plik, a katalogi są traktowane jako pliki. Oznacza to, że FileExistsUTF8('../') pod Uniksem sprawdza istnienie katalogu nadrzędnego, co zwykle daje prawdę.
  
Double path delimiters in file names are also treated differently:  
+
Podwójne separatory ścieżki w nazwach plików są również traktowane inaczej:  
* Windows: 'C:\' is not the same as 'C:\\'
+
* Windows: 'C:\' to nie to samo co 'C:\\'
* Unix like OS: the path '/usr//' is the same as '/usr/'. If '/usr' is a directory then even all three are the same.  
+
* Uniksy: ścieżka '/usr//' jest taka sama jak '/usr/'. Jeśli '/usr' jest katalogiem, to nawet wszystkie trzy zapisy są takie same.
  
This is important when concatenating file names. For example:
+
Jest to ważne przy łączeniu nazw plików. Na przykład:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
FullFilename:=FilePath+PathDelim+ShortFilename; // can result in two PathDelims which gives different results under Windows and Linux
+
FullFilename:=FilePath+PathDelim+ShortFilename; // może skutkować dwoma znakami PathDelims, które dają różne wyniki pod Windows i Linux
FullFilename:=AppendPathDelim(FilePath) + ShortFilename; // creates only one PathDelim
+
FullFilename:=AppendPathDelim(FilePath) + ShortFilename; // tworzy tylko jeden znak PathDelim
FullFilename:=TrimFilename(FilePath+PathDelim+ShortFilename); // creates only one PathDelim and do some more clean up</syntaxhighlight>
+
FullFilename:=TrimFilename(FilePath+PathDelim+ShortFilename); // tworzy tylko jeden znak PathDelim i czyści ścieżkę</syntaxhighlight>
  
The function TrimFilename replaces double path delimiters with single ones and shorten '..' paths. For example /usr//lib/../src is trimmed to /usr/src.
+
Funkcja TrimFilename zastępuje podwójne separatory ścieżek pojedynczymi jedynkami i skraca ścieżki typu '..'. Na przykład /usr//lib/../src jest przekształcony do postaci /usr/src.
  
If you want to know if a directory exists use '''DirectoryExistsUTF8'''.
+
Jeśli chcesz wiedzieć, czy katalog istnieje, użyj '''DirectoryExistsUTF8'''.
  
Another common task is to check if the path part of a file name exists. You can get the path with ExtractFilePath, but this will contain the path delimiter.  
+
Innym częstym zadaniem jest sprawdzenie, czy istnieje ścieżka w nazwie pliku. Ścieżkę można uzyskać za pomocą ExtractFilePath, ale będzie ona zawierać separator ścieżki.
* Under Unix like system you can simply use FileExistsUTF8 on the path. For example FileExistsUTF8('/home/user/') will return true if the directory /home/user exists.  
+
* Under Windows you must use the DirectoryExistsUTF8 function, but before that you must delete the path delimiter, for example with the ChompPathDelim function.  
+
* W systemie uniksowym możesz po prostu użyć FileExistsUTF8 na ścieżce. Na przykład FileExistsUTF8('/home/user/') zwróci true, jeśli katalog /home/user istnieje.
 +
* W systemie Windows musisz użyć funkcji DirectoryExistsUTF8, ale wcześniej musisz usunąć separator ścieżki, na przykład za pomocą funkcji ChompPathDelim.
  
Under Unix like systems the root directory is '/' and using the ChompPathDelim function will create an empty string. The function DirPathExists works like the DirectoryExistsUTF8 function, but trims the given path.
+
W systemach uniksowych katalogiem głównym jest „/”, a użycie funkcji ChompPathDelim utworzy pusty ciąg. Funkcja DirPathExists działa jak funkcja DirectoryExistsUTF8, ale przycina podaną ścieżkę.
  
Note that Unix/Linux uses the '~' (tilde) symbol to stand for the home directory, typically '/home/jim/' for a user called jim. So '~/myapp/myfile' and '/home/jim/myapp/myfile' are identical on the command line and in scripts. However, the tilde is not automatically expanded by Lazarus. It is necessary to use ExpandFileNameUTF8('~/myapp/myfile') to get the full path.
+
Zauważ, że Unix/Linux używa symbolu „~(tylda) oznaczającego katalog domowy, np. „/home/jan/” dla użytkownika zwanego Jan. Tak więc „~/myapp/myfile” i „/home/jan/myapp/myfile” są identyczne w wierszu poleceń i skryptach. Jednak tylda nie jest automatycznie rozwijana przez Lazarusa. Aby uzyskać pełną ścieżkę, konieczne jest użycie ExpandFileNameUTF8('~/myapp/myfile').
  
=== Text encoding ===
+
=== Kodowanie tekstu ===
 
   
 
   
Text files are often encoded in the current system encoding. Under Windows this is usually one of the windows code pages, while Linux, BSD, and macOS usually use UTF-8.  
+
Pliki tekstowe są często kodowane w bieżącym kodowaniu systemowym. W starszych systemach Windows jest to zwykle jedna ze stron kodowych systemu Windows, a w nowszych UTF-16, podczas gdy Linux, BSD i macOS zwykle używają UTF-8. Nie ma zasady, która na 100% da odpowiedź, jakiego kodowania używa plik tekstowy. Moduł LCL '''lconvencoding''' ma funkcję do odgadywania kodowania:
There is no 100% rule to find out which encoding a text file uses. The LCL unit '''lconvencoding''' has a function to guess the encoding:
 
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 132: Line 132:
 
function GetDefaultTextEncoding: string;</syntaxhighlight>
 
function GetDefaultTextEncoding: string;</syntaxhighlight>
  
And it contains functions to convert from one encoding to another:
+
oraz zawiera funkcje do konwersji z jednego kodowania na inne:
  
 
<syntaxhighlight lang="pascal">function ConvertEncoding(const s, FromEncoding, ToEncoding: string): string;
 
<syntaxhighlight lang="pascal">function ConvertEncoding(const s, FromEncoding, ToEncoding: string): string;
  
function UTF8BOMToUTF8(const s: string): string; // UTF8 with BOM
+
function UTF8BOMToUTF8(const s: string): string; // UTF8 z BOM
function ISO_8859_1ToUTF8(const s: string): string; // central europe
+
function ISO_8859_1ToUTF8(const s: string): string; // Europa Środkowa
function CP1250ToUTF8(const s: string): string; // central europe
+
function CP1250ToUTF8(const s: string): string; // Europa Środkowa
function CP1251ToUTF8(const s: string): string; // cyrillic
+
function CP1251ToUTF8(const s: string): string; // cyrylica
function CP1252ToUTF8(const s: string): string; // latin 1
+
function CP1252ToUTF8(const s: string): string; // Latin-1 (Europa Zachodnia)
 
...
 
...
function UTF8ToUTF8BOM(const s: string): string; // UTF8 with BOM
+
function UTF8ToUTF8BOM(const s: string): string; // UTF8 z BOM
function UTF8ToISO_8859_1(const s: string): string; // central europe
+
function UTF8ToISO_8859_1(const s: string): string; // Europa Środkowa
function UTF8ToCP1250(const s: string): string; // central europe
+
function UTF8ToCP1250(const s: string): string; // Europa Środkowa
function UTF8ToCP1251(const s: string): string; // cyrillic
+
function UTF8ToCP1251(const s: string): string; // cyrylica
function UTF8ToCP1252(const s: string): string; // latin 1
+
function UTF8ToCP1252(const s: string): string; // Latin-1 (Europa Zachodnia)
 
...</syntaxhighlight>
 
...</syntaxhighlight>
  
For example to load a text file and convert it to UTF-8 you can use:
+
Na przykład, aby załadować plik tekstowy i przekonwertować go na UTF-8, możesz użyć:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 159: Line 159:
 
   sl:=TStringList.Create;
 
   sl:=TStringList.Create;
 
   try
 
   try
     sl.LoadFromFile('sometext.txt'); // beware: this changes line endings to system line endings
+
     sl.LoadFromFile('jakis_tekst.txt'); // uwaga: zmienia to zakończenia linii na systemowe zakończenia linii
 
     OriginalText:=sl.Text;
 
     OriginalText:=sl.Text;
 
     TextAsUTF8:=ConvertEncoding(OriginalText,GuessEncoding(OriginalText),EncodingUTF8);
 
     TextAsUTF8:=ConvertEncoding(OriginalText,GuessEncoding(OriginalText),EncodingUTF8);
Line 169: Line 169:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
And to save a text file in the system encoding you can use:
+
Aby zapisać plik tekstowy w kodowaniu systemowym, możesz użyć:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
sl.Text:=ConvertEncoding(TextAsUTF8,EncodingUTF8,GetDefaultTextEncoding);
 
sl.Text:=ConvertEncoding(TextAsUTF8,EncodingUTF8,GetDefaultTextEncoding);
sl.SaveToFile('sometext.txt');
+
sl.SaveToFile('jakis_tekst.txt');
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Configuration files ===
+
=== Pliki konfiguracyjne ===
  
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.
+
Możesz użyć funkcji [[doc:rtl/sysutils/getappconfigdir.html|GetAppConfigDir]] z modułu SysUtils, aby uzyskać odpowiednie miejsce do przechowywania plików konfiguracyjnych w innym systemie. Funkcja ma jeden parametr o nazwie Global. Jeśli ma wartość True, zwracany katalog jest katalogiem globalnym, tj. ważnym dla wszystkich użytkowników w systemie. Jeśli parametr Global ma wartość false, katalog jest specyficzny dla użytkownika, który wykonuje program. W systemach, które nie obsługują środowisk wielu użytkowników, te dwa katalogi mogą być takie same.
  
There is also the [[doc:rtl/sysutils/getappconfigfile.html|GetAppConfigFile]] which will return an appropriate name for an application configuration file. You can use it like this:
+
Istnieje również funkcja [[doc:rtl/sysutils/getappconfigfile.html|GetAppConfigFile]], która zwróci odpowiednią nazwę dla pliku konfiguracyjnego aplikacji. Możesz jej użyć w ten sposób:
 
<syntaxhighlight Lang=pascal>
 
<syntaxhighlight Lang=pascal>
 
ConfigFilePath := GetAppConfigFile(False);
 
ConfigFilePath := GetAppConfigFile(False);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Below are examples of the output of default path functions on different systems:
+
Poniżej znajdują się przykłady funkcji wypisujące domyślne ścieżki w różnych systemach:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 202: Line 202:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
You can notice that global configuration files are stored on the /etc directory and local configurations are stored in a hidden directory in the user's home directory. Directories whose name begin with a dot (.) are hidden on UNIX and UNIX-like operating systems. You can create a directory in the location returned by GetAppConfigDir and then store configuration files there.
+
Możesz zauważyć, że w systemie Linux globalne pliki konfiguracyjne przechowywane są w katalogu /etc, a lokalne w ukrytym katalogu w katalogu domowym użytkownika. Katalogi, których nazwa zaczyna się od kropki (.) są ukryte w systemach operacyjnych UNIX i podobnych do UNIX. Możesz utworzyć katalog w lokalizacji zwróconej przez GetAppConfigDir, a następnie przechowywać tam pliki konfiguracyjne.
  
{{Note| Normal users are not allowed to write to the /etc directory. Only users with administration rights can do this.}}
+
{{Note| Zwykli użytkownicy nie mogą pisać do katalogu /etc. Mogą to zrobić tylko użytkownicy z uprawnieniami administratora.}}
  
Notice that before FPC 2.2.4 the function was using the directory where the application was to store global configurations on Windows.
+
Zauważ, że przed FPC 2.2.4 funkcja korzystała z katalogu, w którym aplikacja przechowywała globalne konfiguracje systemu Windows.
  
The output on Windows 98 with FPC 2.2.0:
+
Dane wyjściowe w systemie Windows 98 z FPC 2.2.0:
  
 
<pre>
 
<pre>
Line 217: Line 217:
 
</pre>
 
</pre>
  
The output on Windows XP with FPC 3.0.4:
+
Dane wyjściowe w systemie Windows XP z FPC 3.0.4:
  
 
<pre>
 
<pre>
Line 226: Line 226:
 
</pre>
 
</pre>
  
The output on Windows 7 and Windows 10 and FPC 3.0.4:
+
Dane wyjściowe w systemach Windows 7 i Windows 10 z FPC 3.0.4:
  
 
<pre>
 
<pre>
Line 235: Line 235:
 
</pre>
 
</pre>
  
The output on macOS 10.14.5 with FPC 3.0.4 (violates Apple Guidelines - see [[#macOS|below]] for the correct macOS file locations):
+
Dane wyjściowe w systemie macOS 10.14.5 z FPC 3.0.4 (naruszają Wytyczne Apple — zobacz [[#macOS|poniżej]], aby poznać prawidłowe lokalizacje plików w systemie macOS):
  
 
<pre>
 
<pre>
Line 244: Line 244:
 
</pre>
 
</pre>
  
The output on FreeBSD 12.1 with FPC 3.0.4:
+
Dane wyjściowe na FreeBSD 12.1 z FPC 3.0.4:
  
 
<pre>
 
<pre>
Line 253: Line 253:
 
</pre>
 
</pre>
  
The observant will have noticed a difference between the Windows and non-Windows operating systems output - the Windows output for the <syntaxhighlight lang="pascal" inline>WriteLn(GetAppConfigFile(True));</syntaxhighlight> global configuration code includes a subdirectory but the other operating systems do not. To obtain the same results for non-Windows operating systems, you need to include an additional [[Boolean]] parameter: <syntaxhighlight lang="pascal" inline>WriteLn(GetAppConfigFile(True,True));</syntaxhighlight>.
+
Obserwator może zauważyć różnicę między danymi wyjściowymi systemów operacyjnych Windows i innych niż Windows — dane wyjściowe systemu Windows dla <syntaxhighlight lang="pascal" inline>WriteLn(GetAppConfigFile(True));</syntaxhighlight> globalne ścieżki konfiguracji zawierają podkatalog projektu, ale inne systemy operacyjne nie. Aby uzyskać te same wyniki dla systemów operacyjnych innych niż Windows, należy dołączyć dodatkowy parametr [[Boolean|logiczny]]: <syntaxhighlight lang="pascal" inline>WriteLn(GetAppConfigFile(True,True));</syntaxhighlight>.
  
{{Note| The use of UPX interferes with the use of the GetAppConfigDir and GetAppConfigFile functions.}}
+
{{Note| Użycie UPX zakłóca korzystanie z funkcji GetAppConfigDir i GetAppConfigFile.}}
  
 
==== macOS ====
 
==== macOS ====
  
In most cases configuration files are preference files, which in macOS should be XML files ending with the ".plist" extension and be stored in /Library/Preferences or ~/Library/Preferences with filenames taken from the "Bundle identifier" field in the [[macOS property list files|Info.plist]] file of the [[Application Bundle|application bundle]]. Using .config files in the user directory is a violation of the Apple programming guidelines. See the [[Locating macOS app support, preferences folders]] article for code which handles this in an Apple-compliant manner.
+
W większości przypadków pliki konfiguracyjne to pliki preferencji, które w systemie macOS powinny być plikami XML z rozszerzeniem „.plist” i znajdować się w katalogu /Library/Preferences lub ~/Library/Preferences z nazwami pobranymi z pola „Identyfikator pakietu” w pliku [[macOS property list files|Info.plist]] [[Application Bundle|pakietu aplikacji]]. Używanie plików .config w katalogu użytkownika jest naruszeniem wytycznych programistycznych Apple. Zapoznaj się z artykułem [[Locating macOS app support, preferences folders|Lokalizowanie obsługi aplikacji macOS, foldery preferencji]], aby zapoznać się z kodem, który obsługuje to w sposób zgodny z Apple.
  
=== Data and resource files ===
+
=== Pliki danych i zasobów ===
  
A very common question is where to store data files an application might need, such as Images, Music, XML files, database files, help files, etc. Unfortunately there is no cross-platform function to get the best location to look for data files. The solution is to implement differently on each platform using IFDEFs.
+
Bardzo częstym pytaniem jest, gdzie przechowywać pliki danych, których może potrzebować aplikacja, takie jak obrazy, muzyka, pliki XML, pliki bazy danych, pliki pomocy itp. Niestety nie ma funkcji wieloplatformowej, aby uzyskać najlepszą lokalizację do wyszukiwania plików danych. Rozwiązaniem jest implementacja w inny sposób na każdej platformie przy użyciu IFDEF.
  
 
==== Windows ====
 
==== Windows ====
  
On Windows, application data that the program modifies should not be put in the application's directory (e.g. C:\Program Files\) but in a specific location (see e.g. [http://support.microsoft.com/kb/310294 "Classify Application Data"]). Windows Vista and newer actively enforce this (users only have write access to these directories when using elevation or disabling UAC) but uses a folder redirection mechanism to accommodate older, wrongly-programmed applications. Just reading, not writing, data from application directories would still work but is not recommended.
+
W systemie Windows dane aplikacji, które modyfikuje program, nie powinny być umieszczane w katalogu aplikacji (np. C:\Program Files\), ale w określonej lokalizacji. System Windows Vista i nowsze aktywnie to wymuszają (użytkownicy mają dostęp tylko do zapisu w tych katalogach podczas korzystania z funkcji podnoszenia uprawnień lub wyłączania kontroli konta użytkownika), ale używają mechanizmu przekierowywania folderów, aby uwzględnić starsze, błędnie zaprogramowane aplikacje. Samo odczytywanie, a nie pisanie, danych z katalogów aplikacji nadal działa, ale nie jest to zalecane.
  
In short: use such folder:
+
W skrócie: użyj takiego folderu:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
     OpDirLocal:= GetEnvironmentVariableUTF8('appdata')+'\MyAppName';
 
     OpDirLocal:= GetEnvironmentVariableUTF8('appdata')+'\MyAppName';
 
</syntaxhighlight>
 
</syntaxhighlight>
  
See [[Windows_Programming_Tips#Getting_special_folders_.28My_documents.2C_Desktop.2C_local_application_data.2C_etc.29|Windows Programming Tips - Getting Special Folders]]
+
Zobacz: [[Windows_Programming_Tips#Getting_special_folders_.28My_documents.2C_Desktop.2C_local_application_data.2C_etc.29|Wskazówki dotyczące programowania w systemie Windows — uzyskiwanie specjalnych folderów]]
  
 
==== Unix/Linux ====
 
==== Unix/Linux ====
On most Unixes (like Linux, FreeBSD, OpenBSD, Solaris but '''not macOS'''), application data files are located in a fixed location, which can be something like: /usr/local/share/app_name or /opt/app_name.
 
  
Application data that needs to be written to by the application often gets stored in places like /usr/local/var/app_name, /usr/local/share/app_name or  /usr/local/app_name, with appropriate permissions set.
+
W większości systemów Unix (takich jak Linux, FreeBSD, OpenBSD, Solaris, ale nie '''macOS''') pliki danych aplikacji znajdują się w stałej lokalizacji, która może wyglądać tak: /usr/local/share/nazwa_aplikacji lub /opt/nazwa_aplikacji.
  
Help files (aka man pages) should be stored in /usr/local/man/man[appropriate manual section number]/app_name>, with appropriate permissions set. Note that some FreeBSD and Linux manual sections differ or do not exist.
+
Dane aplikacji, do których aplikacja musi zapisać, często są przechowywane w miejscach takich jak /usr/local/var/nazwa_aplikacji, /usr/local/share/nazwa_aplikacji lub /usr/local/nazwa_aplikacji, z odpowiednimi uprawnieniami.
  
User-specific read/write config/data will normally be stored somewhere under the user's home directory (eg in ~/.config/<programname>). Refer to [[Multiplatform_Programming_Guide#Configuration_files|Configuration Files]] above.
+
Pliki pomocy (inaczej strony podręcznika) powinny być przechowywane w /usr/local/man/man[numer odpowiedniej sekcji podręcznika]/nazwa_aplikacji>, z odpowiednimi uprawnieniami. Zauważ, że niektóre sekcje podręcznika FreeBSD i Linuksa różnią się lub nie istnieją.
 +
 
 +
Pliki konfiguracji/danych do odczytu/zapisu specyficzne dla użytkownika będą zwykle przechowywane gdzieś w katalogu domowym użytkownika (np. w ~/.config/<nazwa programu>). Zapoznaj się z powyższymi [[Multiplatform_Programming_Guide#Pliki_konfiguracyjne|plikami konfiguracyjnymi]].
  
 
==== macOS ====
 
==== macOS ====
  
macOS is an exception among UNIX operating systems. An application is published in a bundle (a directory with ".app" extension) which is treated by the Finder file manager as a file (in a Terminal you can "cd path/myapp.app" or in Finder right click on the app and choose "Show Package Contents"). Your resource files should be located inside the bundle. If the bundle is "path/MyApp.app", then the:
+
macOS jest wyjątkiem wśród systemów operacyjnych UNIX. Aplikacja jest publikowana w pakiecie (katalog z rozszerzeniem „.app”), który jest traktowany przez menedżera plików Finder jako plik (w Terminalu można użyć „cd path/myapp.app” lub w Finderze prawym przyciskiem myszy na aplikacji i wybierz „Show Package Contents” („Pokaż zawartość pakietu”). Twoje pliki zasobów powinny znajdować się wewnątrz pakietu. Jeśli pakiet to „path/MojaAplikacja.app”, to:
  
* executable file is "path/MyApp.app/Contents/MacOS/myapp"
+
* plik wykonywalny to "path/MojaAplikacja.app/Contents/MacOS/myapp"
* resources directory is "path/MyApp.app/Contents/Resources"
+
* katalog zasobów to "path/MojaAplikacja.app/Contents/Resources"
  
Application supplied data and resource files should generally be stored in the Resources directory of the application bundle. For code which handles this in an Apple compliant manner, see the [[Locating the macOS application resources directory]] article.
+
Dane i pliki zasobów dostarczane przez aplikację powinny być zazwyczaj przechowywane w katalogu Resources pakietu aplikacji. Aby zapoznać się z kodem, który obsługuje to w sposób zgodny z Apple, zobacz artykuł [[Locating the macOS application resources directory|Lokalizowanie katalogu zasobów aplikacji systemu macOS]].
  
Application data files  generated by the user should be stored in the user's '~/Library/Application Support' directory. For code which handles this in an Apple compliant manner, see the [[Locating macOS app support, preferences folders]] article.
+
Pliki danych aplikacji wygenerowane przez użytkownika powinny być przechowywane w katalogu użytkownika „~/Library/Application Support”. Aby poznać kod, który obsługuje to w sposób zgodny z Apple, zapoznaj się z artykułem [[Locating macOS app support, preferences folders|Lokalizowanie obsługi aplikacji macOS, foldery preferencji]].
  
{{Warning|'''Never''' use <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight>, or any function which uses it, on any UNIX platform to ''determine'' the location of the executable, as this is a DOS-Windows-OS/2 convention and has several conceptual problems, which cannot be solved using emulation on other platforms. The only thing <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight> is guaranteed to return on UNIX platforms is the name with which the program was started. The directory in which it is located and the name of the actual binary (in case it was started using a symbolic link) are not guaranteed to be available via <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight>. For macOS, you can '''reliably''' locate the application bundle directory using the native code in  [[Locating the macOS application resources directory|this article]].}}
+
{{Warning|'''Nigdy''' nie używaj <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight> ani żadnej funkcji, która go używa, na żadnej platformie UNIX do określenia lokalizacji pliku wykonywalnego, ponieważ jest to konwencja DOS-Windows-OS/2 i ma kilka problemów koncepcyjnych, których nie można rozwiązać za pomocą emulacji na innych platformach. Jedyną rzeczą, którą <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight> gwarantuje na platformach UNIX jest nazwa, pod którą program został uruchomiony. Nie ma gwarancji, że katalog, w którym się znajduje, oraz nazwa rzeczywistego pliku binarnego (w przypadku, gdy został uruchomiony przy użyciu dowiązania symbolicznego) będą dostępne za pośrednictwem <syntaxhighlight lang="pascal" inline>paramStr(0)</syntaxhighlight>. W przypadku systemu macOS można '''niezawodnie''' zlokalizować katalog pakietu aplikacji przy użyciu kodu natywnego opisanego w [[Locating the macOS application resources directory|tym artykule]].}}
  
 
=== 32/64 bit ===
 
=== 32/64 bit ===
  
====Detecting bitness at runtime====
+
====Wykrywanie wersji bitowej systemu w czasie wykonywania====
While you can control whether you compile for 32 or 64 bit with compiler defines, sometimes you want to know what bitness the operating system runs.
+
Chociaż możesz kontrolować, czy kompilujesz dla systemu 32 lub 64-bit za pomocą definicji kompilatora, czasami chcesz wiedzieć, jaka jest bitowość systemu operacyjnego.
For example, if you are running a 32 bit Lazarus program on 64 bit Windows, you might want to run an external program in a 32 bit program files directory, or you might want to give different information to users: I need this in my LazUpdater Lazarus installer to offer the user a choice of 32 and 64 bit compilers. Code: [[Detect Windows x32-x64 example]].
+
Na przykład, jeśli używasz 32-bitowego programu Lazarus w 64-bitowym systemie Windows, możesz chcieć uruchomić zewnętrzny program w katalogu 32-bitowych plików programu lub możesz chcieć przekazać użytkownikom inne informacje: Potrzebuję tego w moim instalatorze Lazarusa LazUpdater oferujący użytkownikowi wybór 32- i 64-bitowych kompilatorów. Przykład kodu: [[Detect Windows x32-x64 example|Wykryj Windows x32-x64]].
  
====Detecting bitness of external library before loading it====
+
====Wykrywanie wersji bitowej zewnętrznej biblioteki przed jej załadowaniem====
When you want to load functions from dynamic library into your program, it has to have same bitness as your application. On 64 bit Windows, your application might be 32-bit or 64-bit, and there can be 32-bit and 64-bit libraries on your system.
+
Kiedy chcesz załadować funkcje z biblioteki dynamicznej do twojego programu, musi ona mieć taką samą wersję bitową jak twoja aplikacja. W 64-bitowym systemie Windows aplikacja może być 32-bitowa lub 64-bitowa, a w systemie mogą znajdować się biblioteki 32-bitowe i 64-bitowe. Więc możesz chcieć sprawdzić, czy wersja bitowa biblioteki dll jest taka sama jak twojej aplikacji przed dynamicznym załadowaniem dll. Oto funkcja testująca wersję bitową dll ([http://forum.lazarus.freepascal.org/index.php/topic,36834.msg245859.html#msg245859 opublikowana na forum przez GetMem]) (komentarze zostały przetłumaczone):
So you might want to check whether dll's bitness is same as your application's bitness before loading the dll dynamically. Here is a function which tests dll's bitness ([http://forum.lazarus.freepascal.org/index.php/topic,36834.msg245859.html#msg245859 contributed in forum by GetMem]):
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
  
Line 313: Line 313:
 
function GetPEType(const APath: WideString): Byte;
 
function GetPEType(const APath: WideString): Byte;
 
const
 
const
   PE_UNKNOWN = 0; //if the file is not a valid dll, 0 is returned
+
   PE_UNKNOWN = 0; //jeśli plik nie jest poprawną biblioteką dll, zwracane jest 0
  // PE_16BIT  = 1; // not supported by this function
+
  // PE_16BIT  = 1; // nieobsługiwane przez tę funkcję
 
   PE_32BIT  = 2;
 
   PE_32BIT  = 2;
 
   PE_64BIT  = 3;
 
   PE_64BIT  = 3;
Line 373: Line 373:
 
end;
 
end;
  
//Now, if you compile your application for 32-bit and 64-bit windows, you can check if dll's bitness is same as your application's:
+
//Teraz, jeśli skompilujesz swoją aplikację dla 32-bitowych i 64-bitowych wersji Windows,
 +
//możesz sprawdzić, czy wersja bitowa dll jest taka sama jak w Twojej aplikacji:
 
function IsCorrectBitness(const APath: WideString): Boolean;
 
function IsCorrectBitness(const APath: WideString): Boolean;
 
begin   
 
begin   
 
   {$ifdef CPU32}
 
   {$ifdef CPU32}
     Result := GetPEType(APath) = 2; //the application is compiled as 32-bit, we ask if GetPeType returns 2
+
     Result := GetPEType(APath) = 2; //aplikacja jest kompilowana jako 32-bitowa, pytamy czy GetPeType zwraca 2
 
   {$endif}
 
   {$endif}
 
   {$ifdef CPU64}
 
   {$ifdef CPU64}
     Result := GetPEType(APath) = 3; //the application is compiled as 64-bit, we ask if GetPeType returns 3
+
     Result := GetPEType(APath) = 3; //aplikacja jest kompilowana jako 64-bitowa, pytamy czy GetPeType zwraca 3
 
   {$endif}
 
   {$endif}
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==== Pointer / Integer Typecasts ====
+
==== Typy wskaźników / liczb całkowitych ====
  
Pointers under 64bit need 8 bytes instead of 4 on 32bit. The 'Integer' type remains 32bit on all platforms for compatibility. This means you can not typecast pointers into integers and back.  
+
Wskaźniki pod architekturą 64-bitową zajmują 8 bajtów zamiast 4 na 32-bitowej. Typ 'Integer' pozostaje 32-bitowy na wszystkich platformach, aby zapewnić zgodność. Oznacza to, że nie możesz rzutować wskaźników na typ Integer i z powrotem.
  
FPC defines two types for this: PtrInt and PtrUInt. PtrInt is a 32bit signed integer on 32 bit platforms and a 64bit signed integer on 64bit platforms. The same for PtrUInt, but ''unsigned'' integer instead.
+
FPC definiuje w tym celu dwa typy: PtrInt i PtrUInt. PtrInt to 32-bitowa liczba całkowita ze znakiem na platformach 32-bitowych i 64-bitowa liczba całkowita ze znakiem na platformach 64-bitowych. To samo dla PtrUInt, ale dla liczb całkowitych bez znaku.
  
Use for code that should work with Delphi and FPC:
+
Użyj dla kodu, który powinien działać z Delphi i FPC:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
  {$IFNDEF FPC}
 
  {$IFNDEF FPC}
Line 400: Line 401:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Replace all '''integer(SomePointerOrObject)''' with '''PtrInt(SomePointerOrObject)'''.
+
Zamień wszystkie rzutowania wskaźnika '''Integer(SomePointerOrObject)''' na '''PtrInt(SomePointerOrObject)'''.
  
=== Endianess ===
+
=== Kolejność bajtów ===
  
Intel platforms are little endian, that means the least significant byte comes first. For example the two bytes of a word $1234 is stored as $34 $12 on little endian systems.
+
Platformy Intela są ''little endian'', co oznacza, że ​​najmniej znaczący bajt jest na pierwszym miejscu. Na przykład dwa bajty słowa $1234 są przechowywane kolejno jako $34 $12 w systemach ''little endian''. W systemach typu ''big endian'', takich jak powerpc, dwa bajty słowa $1234 są przechowywane kolejno jako $12 $34. Różnica jest istotna przy odczytywaniu plików utworzonych na innych systemach.
On big endian systems like the powerpc the two bytes of a word $1234 are stored as $12 $34. The difference is important when reading files created on other systems.
 
  
Use for code that should work on both:
+
Użyj dla kodu, który powinien działać na obu systemach:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
{$IFDEF ENDIAN_BIG}
 
{$IFDEF ENDIAN_BIG}
Line 416: Line 416:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The opposite is ENDIAN_LITTLE.
+
Przeciwieństwo dla ENDIAN_BIG to ENDIAN_LITTLE.
  
The system unit provides plenty of endian converting functions, like SwapEndian, BEtoN (big endian to current endian), LEtoN (little endian to current endian), NtoBE (current endian to big endian) and NtoLE (current endian to little endian).
+
Moduł '''system''' zapewnia wiele funkcji konwertujących ''endian'', takich jak SwapEndian, BEtoN (''big endian'' do bieżącego ''endian''), LEtoN (''little endian'' do bieżącego ''endian''), NtoBE (bieżący ''endian'' do ''big endian'') i NtoLE (bieżący ''endian'' do ''little endian'').
  
 +
==== Libc i inne jednostki specjalne ====
  
==== Libc and other special units ====
+
Unikaj starszych modułów, takich jak „oldlinux” i „libc”, które nie są obsługiwane poza linux/i386.
  
Avoid legacy units like "oldlinux" and "libc" that are not supported outside of linux/i386.
+
==== Asembler ====
  
==== Assembler ====
+
Unikaj używania [[Assembly language|asemblera]].
  
Avoid [[Assembly language|assembler]].
+
==== Dyrektywy kompilatora ====
 
 
==== Compiler defines ====
 
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
{$ifdef CPU32}
 
{$ifdef CPU32}
...write here code for 32 bit processors
+
...tutaj napisz kod dla procesorów 32-bitowych
 
{$ENDIF}
 
{$ENDIF}
 
{$ifdef CPU64}
 
{$ifdef CPU64}
...write here code for 64 bit processors
+
...tutaj napisz kod dla procesorów 64-bitowych
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Projects, packages and search paths ===
+
=== Projekty, pakiety i ścieżki wyszukiwania ===
  
 
Lazarus projects and packages are designed for multi platforms. Normally you can simply copy the project and the required packages to another machine and compile them there. You don't need to create one project per platform.
 
Lazarus projects and packages are designed for multi platforms. Normally you can simply copy the project and the required packages to another machine and compile them there. You don't need to create one project per platform.
 +
Projekty i pakiety Lazarusa są przeznaczone dla wielu platform. Zwykle możesz po prostu skopiować projekt i wymagane pakiety na inny komputer i tam je skompilować. Nie musisz tworzyć osobnego projektu dla każdej platformy.
  
Some advice to achieve this
+
Kilka rad, jak to osiągnąć.
  
The compiler creates for every unit a ppu with the same name. This ppu can be used by other projects and packages. The unit source files (e.g. unit1.pas) should not be shared. Simply give the compiler a unit output directory where to create the ppu files. The IDE does that by default, so nothing to do for you here.
+
Kompilator tworzy dla każdego modułu plik ppu o tej samej nazwie. Ten plik ppu może być używany przez inne projekty i pakiety. Pliki źródłowe modułu (np. unit1.pas) nie powinny być udostępniane. Po prostu daj kompilatorowi katalog wyjściowy modułu, w którym ma tworzyć pliki ppu. IDE robi to domyślnie, więc nie ma tu nic do roboty.
  
Every unit file must be part of '''one''' project or package. If a unit file is only used by a single project, add it to this project. Otherwise add it to a package. If you have not yet created a package for your shared units, see here: [[Lazarus_Packages#Creating a package for your common units|Creating a package for your common units]]
+
Każdy plik modułu musi być częścią '''jednego''' projektu lub pakietu. Jeśli plik modułu jest używany tylko w jednym projekcie, dodaj go do tego projektu. W przeciwnym razie dodaj go do pakietu. Jeśli jeszcze nie utworzyłeś pakietu dla swoich modułów współdzielonych, zobacz tutaj: [[Lazarus_Packages#Creating a package for your common units|Tworzenie pakietu dla wspólnych modułów]].
  
Every project and every package should have '''disjunct directories''' - they should not share directories. Otherwise you must be an expert in the art of compiler search paths. If you are not an expert or if others who may use your project/package are not experts: do not share directories between projects/packages.
+
Każdy projekt i każdy pakiet powinien mieć '''oddzielne katalogi''' - nie powinny one współdzielić katalogów. W przeciwnym razie musisz być ekspertem w dziedzinie ścieżek wyszukiwania kompilatora. Jeśli nie jesteś ekspertem lub jeśli inne osoby, które mogą korzystać z Twojego projektu/pakietu, nie są ekspertami: nie twórz wspólnego katalogu dla projektów i pakietów.
  
==== Platform specific units ====
+
==== Moduły zależne od platformy ====
For example the unit wintricks.pas should only be used under Windows. In the uses section use:
+
Na przykład moduł wintricks.pas powinien być używany tylko w systemie Windows. W sekcji '''uses''' użyj:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 464: Line 464:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
If the unit is part of a package, you must also select the unit in the package editor of the package and disable the ''Use unit'' checkbox.
+
Jeśli moduł jest częścią pakietu, należy również wybrać ten moduł w edytorze pakietów i odznaczyć pole wyboru ''Use unit''.
  
See also [[Lazarus_Packages#Platform_specific_units|Platform specific units]]
+
Zobacz także [[Lazarus_Packages#Platform_specific_units|Moduły zależne od platformy]]
  
==== Platform specific search paths ====
+
==== Ścieżki wyszukiwania specyficzne dla platformy ====
  
When you target several platforms and access the operating system directly, then you will quickly get tired of endless IFDEF constructions. One solution that is used often in the FPC and Lazarus sources is to use include files. Create one sub directory per target. For example win32, linux, bsd, darwin. Put into each directory an include file with the same name. Then use a macro in the include path. The unit can use a normal include directive.
 
  
An example for one include file for each LCL widget set:
+
Kiedy wybierasz kilka platform i masz bezpośredni dostęp do systemu operacyjnego, szybko zmęczysz się niekończącymi się konstrukcjami IFDEF. Jednym z rozwiązań często stosowanych w źródłach FPC i Lazarus jest użycie plików dołączanych (include files). Utwórz jeden podkatalog na każdą docelową platformę. Na przykład win32, linux, bsd, darwin. Umieść w każdym katalogu plik dołączany o tej samej nazwie. Następnie użyj makra w ścieżce include. Moduł może używać normalnej dyrektywy include.
  
Create one file for each widget set you want to support:
+
Przykład jednego pliku include dla każdego zestawu widżetów LCL:
 +
 
 +
Utwórz jeden plik dla każdego zestawu widżetów, który chcesz obsługiwać:
 
  win32/example.inc
 
  win32/example.inc
 
  gtk/example.inc
 
  gtk/example.inc
Line 480: Line 481:
 
  carbon/example.inc
 
  carbon/example.inc
  
You do not need to add the files to the package or project.
+
Nie musisz dodawać plików do pakietu lub projektu.
Add the include search path ''$(LCLWidgetType)'' to the compiler options of your package or project.
+
Dodaj ścieżkę wyszukiwania include ''$(LCLWidgetType)'' do opcji kompilatora pakietu lub projektu.
  
In your unit use the directive:
+
W swoim module użyj dyrektywy:
 
{$I example.inc}
 
{$I example.inc}
  
Here are some useful macros and common values:
+
Oto kilka przydatnych makr i typowych wartości:
 
*LCLWidgetType: win32, gtk, gtk2, qt, carbon, fpgui, nogui
 
*LCLWidgetType: win32, gtk, gtk2, qt, carbon, fpgui, nogui
 
*TargetOS: linux, win32, win64, wince, freebsd, netbsd, openbsd, darwin (many more)
 
*TargetOS: linux, win32, win64, wince, freebsd, netbsd, openbsd, darwin (many more)
Line 492: Line 493:
 
*SrcOS: win, unix
 
*SrcOS: win, unix
  
You can use the $Env() macro to use environment variables.
+
Do używania zmiennych środowiskowych można użyć makra $Env().
  
And of course you can use combinations. For example the LCL uses:  
+
I oczywiście możesz używać ich kombinacji. Na przykład LCL wykorzystuje:
  
 
  $(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS);$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType)
 
  $(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS);$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType)
  
See here the complete list of macros: [[IDE Macros in paths and filenames]]
+
Zobacz tutaj pełną listę makr: [[IDE Macros in paths and filenames|Makra IDE w ścieżkach i nazwach plików]].
  
==== Machine / User specific search paths ====
+
==== Ścieżki wyszukiwania specyficzne dla maszyny/użytkownika ====
  
For example you have two windows machines stan and oliver. On stan your units are in ''C:\units'' and on oliver your units are in ''D:\path''. The units belong to the package ''SharedStuff'' which is ''C:\units\sharedstuff.lpk'' on stan and ''D:\path\sharedstuff.lpk'' on oliver.
+
Na przykład masz dwa komputery z systemem Windows, '''stan''' i '''oliver'''. W komputerze ''''stan''' twoje moduły znajdują się w ''C:\units'', a na '''oliver''' w ''D:\path''. Moduły należą do pakietu ''SharedStuff'', który jest w pliku ''C:\units\sharedstuff.lpk'' na '''stan''' i i w pliku ''D:\path\sharedstuff.lpk'' na '''oliver'''.  
Once you opened the lpk in the IDE or by lazbuild, the path is automatically stored in its configuration files (packagefiles.xml).
+
Po otwarciu pliku lpk w IDE lub przez lazbuild, ścieżka jest automatycznie zapisywana w jego plikach konfiguracyjnych (packagefiles.xml). Podczas kompilowania projektu, który wymaga pakietu ''SharedStuff'', IDE i lazbuild wiedzą, gdzie on jest. Więc nie jest potrzebna konfiguracja.
When compiling a project that requires the package ''SharedStuff'', the IDE and lazbuild knows where it is. So no configuration is needed.
 
  
If you have want to deploy a package over many machine or for all users of a machine (e.g. a pool for students), then you can add a lpl file in the lazarus source directory. See packager/globallinks for examples.
+
Jeśli chcesz wdrożyć pakiet na wielu maszynach lub dla wszystkich użytkowników maszyny (np. basen dla studentów), możesz dodać plik lpl w katalogu źródłowym lazarusa. Zobacz katalog Lazarusa packager/globallinks, aby zapoznać się z przykładami.
  
=== Locale differences ===
+
=== Różnice regionalne ===
  
Some functions from Free Pascal, like StrToFloat behave differently depending on the current [locale]]. For example, in the USA the [[DecimalSeparator|decimal separator]] is usually ".", but in many European and South American countries it is ",". This can be a problem as sometimes it is desired to have these functions behave in a fixed way, independently from the locale.  
+
Niektóre funkcje z Free Pascal, takie jak StrToFloat, zachowują się różnie w zależności od ustawień bieżącego [[locale|regionu]]. Na przykład w USA separatorem dziesiętnym jest zwykle „., ale w wielu krajach Europy (w tym w Polsce) i Ameryki Południowej jest to „,. Może to stanowić problem, ponieważ czasami pożądane jest, aby te funkcje zachowywały się w ustalony sposób, niezależnie od ustawień regionalnych. Przykładem jest format pliku z kropkami dziesiętnymi, które zawsze należy interpretować w ten sam sposób.
An example is a file format with decimal points that always needs to be interpreted the same way.
 
  
The next sections explain how to do that.
+
Następne sekcje wyjaśniają, jak to zrobić.
  
 
==== macOS ====
 
==== macOS ====
  
Refer to the [[Locale settings for macOS]] article for details of setting the locale on macOS.
+
Zapoznaj się z artykułem [[Locale settings for macOS|Ustawienia regionalne dla systemu macOS]], aby uzyskać szczegółowe informacje na temat ustawiania języka w systemie macOS.
  
 
====StrToFloat====
 
====StrToFloat====
  
A new set of format settings which set a fixed decimal separator can be created with the following code:
+
Nowy zestaw ustawień formatu, który ustawia stały separator dziesiętny, można utworzyć za pomocą następującego kodu:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// in your .lpr project file
+
// w pliku projektu .lpr
 
uses
 
uses
 
...
 
...
 
{$IFDEF UNIX}
 
{$IFDEF UNIX}
 
clocale  
 
clocale  
{ required on Linux/Unix for formatsettings support. Should be one of the first (probably after cthreads?}
+
{ wymagane w systemie Linux/Unix do obsługi ustawień formatów. Powinien być jednym z pierwszych (prawdopodobnie po cthreads?}
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 536: Line 535:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// in your code:
+
// w twoim kodzie:
 
var
 
var
 
   FPointSeparator, FCommaSeparator: TFormatSettings;
 
   FPointSeparator, FCommaSeparator: TFormatSettings;
 
begin
 
begin
 
   // Format settings to convert a string to a float
 
   // Format settings to convert a string to a float
 +
  // Ustawienia formatu, aby przekonwertować ciąg string na liczbę zmiennoprzecinkowąq
 
   FPointSeparator := DefaultFormatSettings;
 
   FPointSeparator := DefaultFormatSettings;
 
   FPointSeparator.DecimalSeparator := '.';
 
   FPointSeparator.DecimalSeparator := '.';
   FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
+
   FPointSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
 
   FCommaSeparator := DefaultFormatSettings;
 
   FCommaSeparator := DefaultFormatSettings;
 
   FCommaSeparator.DecimalSeparator := ',';
 
   FCommaSeparator.DecimalSeparator := ',';
   FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator
+
   FCommaSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Later on you can use this format settings when calling StrToFloat, like this:
+
Później możesz użyć tych ustawień formatu podczas wywoływania StrToFloat, na przykład:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// This function works like StrToFloat, but simply tries two possible decimal separator
+
// Ta funkcja działa jak StrToFloat, ale po prostu próbuje dwóch możliwych separatorów dziesiętnych
// This will avoid an exception when the string format doesn't match the locale
+
// Pozwoli to uniknąć wyjątku, gdy format ciągu string nie pasuje do ustawień regionalnych
 
function AnSemantico.StringToFloat(AStr: string): Double;
 
function AnSemantico.StringToFloat(AStr: string): Double;
 
begin
 
begin
Line 561: Line 561:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Gtk2 and masking FPU exceptions ===
+
=== Gtk2 i maskowanie wyjątków FPU ===
  
Gtk2 library changes the default value of FPU (floating point unit) exception mask. The consequence of this is that some floating point exceptions do not get raised if Gtk2 library is used by the application. That means that, if for example you develop a LCL application on Windows with win32/64 widgetset (which is Windows default) and plan to compile for Linux (where Gtk2 is default widgetset), you should keep this incompatibilities in mind.
+
Biblioteka Gtk2 zmienia domyślną wartość maski wyjątków FPU (koprocesor - jednostka zmiennoprzecinkowa). Konsekwencją tego jest to, że niektóre wyjątki zmiennoprzecinkowe nie są zgłaszane, jeśli aplikacja korzysta z biblioteki Gtk2. Oznacza to, że jeśli na przykład tworzysz aplikację LCL w systemie Windows z zestawem widżetów win32/64 (który jest domyślnym systemem Windows) i planujesz kompilację dla systemu Linux (gdzie Gtk2 jest domyślnym zestawem widżetów), powinieneś pamiętać o tych niezgodnościach.
  
After [http://www.lazarus.freepascal.org/index.php/topic,13460.0.html this forum topic] and answers on [http://bugs.freepascal.org/view.php?id=19674 this bug report] it became clear that nothing can be done about this, so we must know what actually these differences are.
+
Po [http://www.lazarus.freepascal.org/index.php/topic,13460.0.html tym zgłoszeniu na forum] i odpowiedziach na [http://bugs.freepascal.org/view.php?id=19674 ten raport o błędzie] stało się jasne, że nic nie można z tym zrobić, więc musimy wiedzieć, czym właściwie są te różnice.
  
Therefore, let's do a test:
+
Dlatego zróbmy test:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 591: Line 591:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Our simple program will get what FPC default is:
+
Nasz prosty program otrzyma domyślne wartości FPC:
  
 
<pre>
 
<pre>
Line 602: Line 602:
 
</pre>
 
</pre>
  
However, with Gtk2, only exOverflow is not masked.
+
Jednak w przypadku Gtk2 tylko exOverflow nie jest maskowany.
  
The consequence is that EInvalidOp and EZeroDivide exceptions do not get raised if the application links to Gtk2 library! Normally, dividing non-zero value by zero raises EZeroDivide exception and dividing zero by zero raises EInvalidOp. For example the code like this:
+
Konsekwencją jest to, że wyjątki EInvalidOp i EZeroDivide nie są zgłaszane, jeśli aplikacja łączy się z biblioteką Gtk2! Zwykle dzielenie wartości niezerowej przez zero powoduje wyjątek EZeroDivide, a dzielenie zera przez zero powoduje zwiększenie EInvalidOp. Na przykład taki kod:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 613: Line 613:
 
try
 
try
 
   X := A / B;
 
   X := A / B;
   // code block 1
+
   // blok kodu 1
 
except   
 
except   
   // code block 2
+
   // blok kodu 2
 
end;
 
end;
 
// ...
 
// ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
will take different direction when compiled in application with Gtk2 widgetset. On win widgetset, when B equals zero, an exception will get raised (EZeroDivide or EInvalidOp, depending on whether A is zero) and "code block 2" will be executed. On Gtk2 X becomes [http://www.freepascal.org/docs-html/rtl/math/infinity.html Infinity], [http://www.freepascal.org/docs-html/rtl/math/neginfinity.html NegInfinity], or [http://www.freepascal.org/docs-html/rtl/math/nan.html NaN] and "code block 1" will be executed.
+
przyjmie inny kierunek po skompilowaniu w aplikacji z zestawem widżetów Gtk2. W zestawie widżetów win, gdy B jest równe zero, zostanie zgłoszony wyjątek (EZeroDivide lub EInvalidOp, w zależności od tego, czy A jest zerem) i zostanie wykonany „blok kodu 2”. Na Gtk2 X staje się [http://www.freepascal.org/docs-html/rtl/math/infinity.html Infinity], [http://www.freepascal.org/docs-html/rtl/math/neginfinity.html NegInfinity] lub [http://www.freepascal.org/docs-html/rtl/math/nan.html NaN] i „blok kodu 1” zostanie wykonany.
  
We can think of different ways to overcome this inconsistency. Most of the time you can simply test if B equals zero and don't try the dividing in that case. However, sometimes you will need some different approach. So, take a look at the following examples:
+
Możemy wymyślić różne sposoby przezwyciężenia tej niespójności. W większości przypadków możesz po prostu sprawdzić, czy B jest równe zero i nie próbować dzielić w takim przypadku. Czasami jednak będziesz potrzebować innego podejścia. Spójrz więc na następujące przykłady:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 635: Line 635:
 
try
 
try
 
   X := A / B;
 
   X := A / B;
   Ind := IsInfinite(X) or IsNan(X); // with gtk2, we fall here
+
   Ind := IsInfinite(X) or IsNan(X); // z gtk2 wpadamy tutaj
 
except   
 
except   
   Ind := True; // in windows, we fall here when B equals zero
+
   Ind := True; // w Windows wpadamy tutaj, gdy B równa się zero
 
end;
 
end;
 
if Ind then begin
 
if Ind then begin
   // code block 2
+
   // blok kodu 2
 
end else begin
 
end else begin
   // code block 1
+
   // blok kodu 1
 
end;
 
end;
 
// ...
 
// ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Or:
+
Lub:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
uses
 
uses
Line 660: Line 660:
 
try
 
try
 
   FPUExceptionMask := GetExceptionMask;
 
   FPUExceptionMask := GetExceptionMask;
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]); // unmask
+
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]); // niemaskowane
 
   try
 
   try
 
     X := A / B;
 
     X := A / B;
 
   finally
 
   finally
     SetExceptionMask(FPUExceptionMask); // return previous masking immediately, we must not let Gtk2 internals to be called without the mask
+
     SetExceptionMask(FPUExceptionMask); // natychmiast zwróć poprzednie maskowanie, nie możemy pozwolić, aby wewnętrzne elementy Gtk2 były wywoływane bez maski
 
   end;
 
   end;
   // code block 1
+
   // blok kodu 1
 
except   
 
except   
   // code block 2
+
   // blok kodu 2
 
end;
 
end;
 
// ...
 
// ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Be cautious, do not do something like this (call LCL with still removed mask):
+
Bądź ostrożny, nie rób czegoś takiego (wywołanie LCL z wciąż zdjętą maską):
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
try
 
try
Line 679: Line 679:
 
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
 
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
 
   try
 
   try
     Edit1.Text := FloatToStr(A / B); // NO! Setting Edit's text goes down to widgetset internals and Gtk2 API must not be called without the mask!
+
     Edit1.Text := FloatToStr(A / B); // NIE! Ustawienie tekstu Edit sprowadza się do wewnętrznych widżetów, a API Gtk2 nie może być wywoływane bez maski!
 
   finally
 
   finally
 
     SetExceptionMask(FPUExceptionMask);
 
     SetExceptionMask(FPUExceptionMask);
 
   end;
 
   end;
   // code block 1
+
   // blok kodu 1
 
except   
 
except   
   // code block 2
+
   // blok kodu 2
 
end;
 
end;
 
// ...
 
// ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
But use an auxiliary variable:
+
Ale użyj zmiennej pomocniczej:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
try
 
try
Line 696: Line 696:
 
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
 
   SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
 
   try
 
   try
     X := A / B; // First, we set auxiliary variable X
+
     X := A / B; // Najpierw ustawiamy zmienną pomocniczą X
 
   finally
 
   finally
 
     SetExceptionMask(FPUExceptionMask);
 
     SetExceptionMask(FPUExceptionMask);
 
   end;
 
   end;
   Edit1.Text := FloatToStr(X); // Now we can set Edit's text.
+
   Edit1.Text := FloatToStr(X); // Teraz możemy ustawić tekst w Edit.
   // code block 1
+
   // blok kodu 1
 
except   
 
except   
   // code block 2
+
   // blok kodu 2
 
end;
 
end;
 
// ...
 
// ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
In all situations, when developing LCL applications, it is most important to know about this and to keep in mind that some floating point operations can go different way with different widgetsets. Then you can think of an appropriate way to workaround this, but this should not go unnoticed.
+
We wszystkich sytuacjach podczas tworzenia aplikacji LCL najważniejsze jest, aby o tym wiedzieć i pamiętać, że niektóre operacje zmiennoprzecinkowe mogą przebiegać w inny sposób z różnymi zestawami widżetów. Następnie możesz wymyślić odpowiedni sposób na obejście tego, ale nie powinno to pozostać niezauważone.
  
==Issues when moving from Windows to *nix etc==
+
==Problemy przy przejściu z systemu Windows do *nix itp.==
Issues specific to Linux, macOS, Android and other Unixes are described here. Not all subjects may apply to all platforms
+
W tym miejscu opisano problemy specyficzne dla systemów Linux, macOS, Android i innych Uniksów. Nie wszystkie tematy mogą dotyczyć wszystkich platform.
  
=== On Unix there is no "application directory" ===
+
=== W Uniksie nie ma „katalogu aplikacji” ===
  
Many programmers are used to calling 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 wrong on unixes. The string on ParamStr(0) may contain a directory other than the one of the executable, and it also varies between different shell programs (sh, bash, etc).
+
Wielu programistów jest przyzwyczajonych do wywoływania ExtractFilePath(ParamStr(0)) lub Application.ExeName w celu uzyskania lokalizacji pliku wykonywalnego, a następnie wyszukiwania plików niezbędnych do wykonania programu (obrazy, pliki XML, pliki bazy danych itp.) na podstawie lokalizacji pliku wykonywalnego. To jest złe na unixach. Ciąg w ParamStr(0) może zawierać katalog inny niż plik wykonywalny, a także różni się między różnymi programami powłoki (sh, bash, itp.).
  
Even if Application.ExeName could in fact know the directory where the executable is, that file could be a symbolic link, so you could get the directory of the link instead (depending on the Linux kernel version, you either get the directory of the link or of the program binary itself).
+
Nawet jeśli Application.ExeName może w rzeczywistości znać katalog, w którym znajduje się plik wykonywalny, plik ten może być dowiązaniem symbolicznym, więc zamiast tego można uzyskać katalog dowiązania (w zależności od wersji jądra Linux można uzyskać katalog dowiązania lub samego programu binarnego).
  
To avoid this read the sections about [[Multiplatform_Programming_Guide#Configuration_files|configuration files]] and [[Multiplatform_Programming_Guide#Data_and_resource_files|data files]].
+
Aby tego uniknąć, przeczytaj sekcje dotyczące [[Multiplatform_Programming_Guide/pl#Pliki_konfiguracyjne|plików konfiguracyjnych]] i [[Multiplatform_Programming_Guide/pl#Pliki_danych_i_zasob.C3.B3w|plików danych]].
  
=== Making do without Windows COM Automation ===
+
=== Obycie się bez Windows COM Automation ===
  
With Windows, COM 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 COM Automation client and a COM Automation server, meaning it can both manipulate other programs and in turn be manipulated by other programs. For examples,  
+
W systemie Windows Automatyzacja COM jest potężnym sposobem nie tylko na zdalne manipulowanie innymi programami, ale także na umożliwienie innym programom manipulowania Twoim programem. Dzięki Delphi możesz uczynić swój program zarówno klientem COM Automation, jak i serwerem COM Automation, co oznacza, że ​​może on zarówno manipulować innymi programami, jak i być manipulowany przez inne programy. Aby zapoznać się z przykładami, zobacz [http://wiki.lazarus.freepascal.org/Office_Automation#Using_COM_Automation_to_interact_with_OpenOffice_and_Microsoft_Office Używanie automatyzacji COM do interakcji z pakietami OpenOffice i Microsoft Office].
see [http://wiki.lazarus.freepascal.org/Office_Automation#Using_COM_Automation_to_interact_with_OpenOffice_and_Microsoft_Office Using COM Automation to interact with OpenOffice and Microsoft Office].
 
  
==== macOS alternative ====
+
==== alternatywa dla macOS ====
Unfortunately, COM Automation isn't available on macOS and Linux. However, you can simulate some of the functionality of COM Automation on macOS using AppleScript.
+
Niestety, COM Automation nie jest dostępna w systemach macOS i Linux. Można jednak symulować niektóre funkcje COM Automation w systemie macOS za pomocą AppleScript.
  
AppleScript is similar to COM 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 jest pod pewnymi względami podobny do COM Automation. Na przykład możesz pisać skrypty, które manipulują innymi programami. Oto bardzo prosty przykład AppleScript, który uruchamia NeoOffice (wersja OpenOffice.org na Maca):
  
 
<syntaxhighlight lang="applescript">
 
<syntaxhighlight lang="applescript">
Line 737: Line 736:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
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 macOS 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:
+
Aplikacja zaprojektowana do manipulowania przez AppleScript udostępnia „słownik” klas i poleceń, których można używać z aplikacją, podobnie jak klasy serwera Windows Automation. Jednak nawet aplikacje, takie jak NeoOffice, które nie udostępniają słownika, nadal będą odpowiadać na polecenia „launch” (uruchom), „activate” (aktywuj) i „quit” (wyjście). AppleScript można uruchomić z edytora skryptów macOS lub Findera, a nawet przekonwertować na aplikację, którą można upuścić do stacji dokującej, tak jak każdą aplikację. Możesz także uruchomić AppleScript ze swojego programu, jak w tym przykładzie:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 743: Line 742:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This assumes the script is in the indicated file. You can also run scripts on the fly from your app using the macOS OsaScript command:
+
Zakłada się, że skrypt znajduje się we wskazanym pliku. Możesz także uruchamiać skrypty w locie ze swojej aplikacji za pomocą polecenia macOS OsaScript:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
   fpsystem('osascript -e '#39'tell application "NeoOffice"'#39 +
 
   fpsystem('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}
+
         {Zwróć uwagę na użycie #39 jako pojedynczego cudzysłowu do parametrów}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
However, these examples are just the equivalent of the following Open command:
+
Jednak te przykłady są tylko odpowiednikiem następującego polecenia Open (otwórz):
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 757: Line 756:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Similarly, in macOS you can emulate the Windows shell commands to launch a web browser and launch an email client with:
+
Podobnie w systemie macOS można emulować polecenia powłoki systemu Windows, aby uruchomić przeglądarkę internetową i uruchomić klienta poczty e-mail za pomocą:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 763: Line 762:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
and
+
i
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 769: Line 768:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
which assumes, fairly safely, that a macOS system will have the Safari and Mail applications installed. Of course, you should never make assumptions like this, and for the two previous examples, you can in fact just rely on macOS to do the right thing and pick the user's default web browser and email client if you instead use these variations:
+
co zakłada, dość bezpiecznie, że system macOS będzie miał zainstalowane aplikacje Safari i Mail. Oczywiście nigdy nie należy przyjmować takich założeń, a w przypadku dwóch poprzednich przykładów można po prostu polegać na systemie macOS, aby postępować właściwie i wybrać domyślną przeglądarkę internetową i klienta poczty e-mail użytkownika, jeśli zamiast tego użyjesz tych odmian:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 775: Line 774:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
and
+
i
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 781: Line 780:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Do not forget to include the Unix unit in your uses clause if you use <code>fpsystem</code> or <code>shell</code> (interchangeable).
+
Nie zapomnij dołączyć modułu Unix do klauzuli uses, jeśli używasz <code>fpsystem</code> lub <code>shell</code> (wymiennie).
 +
 
 +
Prawdziwą mocą AppleScript jest zdalne manipulowanie programami w celu tworzenia i otwierania dokumentów oraz automatyzacji innych czynności. To, ile możesz zrobić z programem, zależy od tego, jak obszerny jest jego słownik AppleScript (jeśli taki posiada). Na przykład programy Microsoft Office X nie są zbyt użyteczne z AppleScript, podczas gdy nowsze programy Office 2004 mają całkowicie przepisane słowniki AppleScript, które pod wieloma względami porównywalne są z tym, co jest dostępne za pośrednictwem serwerów Windows Office Automation.
  
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 usable 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.
+
==== Alternatywy dla Linuksa ====
 +
Chociaż powłoki Linuksa obsługują zaawansowane skrypty wiersza poleceń, typ skryptów jest ograniczony do tego, co można przekazać do programu w wierszu poleceń. Nie ma jednego, zunifikowanego sposobu, aby uzyskać dostęp do wewnętrznych klas i poleceń programu w systemie Linux w taki sposób, w jaki są one dostępne, za pośrednictwem Windows COM Automation i macOS AppleScript. Jednak indywidualne środowiska graficzne (GNOME/KDE) i frameworki aplikacji często zapewniają takie metody komunikacji międzyprocesowej. W GNOME zobacz Komponenty Bonobo. KDE posiada framework KParts, DCOP. OpenOffice ma neutralne dla platformy API do zdalnego sterowania biurem (Google OpenOffice SDK) – chociaż prawdopodobnie, aby go używać, będziesz musiał napisać kod łączący w innym języku, który ma powiązania (takie jak Python). Ponadto niektóre aplikacje mają „tryby serwera” aktywowane przez specjalne opcje wiersza polecenia, które umożliwiają sterowanie nimi z innego procesu. Możliwe jest również (Borland zrobił to za pomocą przeglądarki dokumentów Kylix) „osadzenie” jednego okna aplikacji X najwyższego poziomu w innym za pomocą XReparentWindow (chyba).
  
==== Linux alternatives ====
+
Podobnie jak w przypadku systemu Windows, wiele programów dla systemów MacOS i Linux składa się z wielu plików bibliotek (rozszerzenia .dylib i .so). Czasami te biblioteki są zaprojektowane tak, abyś mógł ich używać również w programach, które piszesz. Chociaż może to być sposób na dodanie niektórych funkcji zewnętrznego programu do twojego programu, nie jest to tak naprawdę to samo, co uruchamianie i manipulowanie samym zewnętrznym programem. Zamiast tego twój program po prostu łączy się i używa biblioteki programu zewnętrznego, podobnie jak używałby dowolnej biblioteki programistycznej.
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. There is no single, unified way to access a program's internal classes and commands  with Linux the way they are via Windows COM Automation and macOS AppleScript. However, individual desktop environments (GNOME/KDE) and application frameworks often provide such methods of interprocess communication. On GNOME see Bonobo Components. KDE has the KParts framework, DCOP. OpenOffice has a platform neutral API for controlling the office remotely (google OpenOffice SDK) - though you would probably have to write glue code in another language that has bindings (such as Python) to use it. In addition, some applications have "server modes" activated by special command-line options that allow them to be controlled from another process. It is also possible (Borland did it with Kylix document browser) to "embed" one top-level X application window into another using XReparentWindow (I think).
 
  
As with Windows, many macOS 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.
+
=== Alternatywy dla funkcji Windows API ===
  
=== Alternatives for Windows API functions ===
+
Wiele programów systemu Windows intensywnie korzysta z interfejsu API systemu Windows. W aplikacjach wieloplatformowych funkcje Win API w module Windows nie powinny być używane lub powinny być zawarte w kompilacji warunkowej (np. {$IFDEF MSWINDOWS} ).
  
Many Windows programs use the Windows API extensively. In cross-platform applications Win API functions in the Windows unit should not be used, or should be enclosed by a conditional compile (e.g. {$IFDEF MSWINDOWS} ).
+
Na szczęście wiele z powszechnie używanych funkcji Windows API jest zaimplementowanych wieloplatformowo w module lclintf. Może to być rozwiązanie dla programów, które w dużym stopniu opierają się na API Windows, chociaż najlepszym rozwiązaniem jest zastąpienie tych wywołań prawdziwymi wieloplatformowymi komponentami z LCL. Na przykład można zastąpić wywołania funkcji malowania GDI za pomocą wywołania metod obiektu TCanvas.
  
Fortunately many of the commonly used Windows API functions are implemented in a multiplatform way in the unit [[lclintf]]. This can be a solution for programs which rely heavily on the Windows API, although the best solution is to replace these calls with true cross-platform components from the LCL. You can replace calls to GDI painting functions with calls to a TCanvas object's methods, for example.
+
=== Kody klawiszy ===
 +
Na szczęście wykrywanie kodów klawiszy (np. w zdarzeniach KeyUp) jest przenośne: patrz [[LCL Key Handling|Obsługa klawiszy LCL]].
  
=== Key codes ===
+
===Instalowanie swojej aplikacji===
Fortunately, detecting key codes (e.g. on KeyUp events) is portable: see [[LCL Key Handling]].
+
Zobacz [[Deploying Your Application|Wdrażanie swojej aplikacji]].
  
===Installing your application===
+
== Zobacz także ==
See [[Deploying Your Application]].
 
  
== See also ==
+
* [[Writing portable code regarding the processor architecture|Pisanie przenośnego kodu dotyczącego architektury procesora]]
 +
* [[Introduction to platform-sensitive development|Wprowadzenie do rozwoju zależnego od platformy]]
 +
* [[Apple-specific UI elements|Elementy interfejsu użytkownika specyficzne dla Apple]]
  
* [[Writing portable code regarding the processor architecture]]
+
== Linki zewnętrzne ==
* [[Introduction to platform-sensitive development]]
 
* [[Apple-specific UI elements]]
 
  
== External links ==
+
* http://www.midnightbeach.com/KylixForDelphiProgrammers.html Przewodnik dla programistów Windows zaczynających pracę z Kylix. Wiele pojęć / fragmentów kodu dotyczy Lazarusa.
  
* http://www.midnightbeach.com/KylixForDelphiProgrammers.html A guide for Windows programmers starting with Kylix. Many of concepts / code snippets apply to Lazarus.
+
* http://www.stack.nl/~marcov/porting.pdf Przewodnik po pisaniu przenośnego kodu źródłowego, głównie pomiędzy różnymi kompilatorami.
* http://www.stack.nl/~marcov/porting.pdf A guide for writing portable source code, mainly between different compilers.
 

Latest revision as of 01:39, 2 November 2021

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

Przewodnik programowania wieloplatformowego

To jest samouczek dotyczący pisania aplikacji wieloplatformowych z Lazarusem i Free Pascalem. Obejmuje niezbędne środki ostrożności, aby pomóc w stworzeniu wieloplatformowego programu gotowego do wdrożenia.

Większość aplikacji LCL działa na wielu platformach bez dodatkowej pracy. Ta zasada nazywa się „napisz raz, kompiluj wszędzie”.

Wprowadzenie do programowania wieloplatformowego (międzyplatformowego)

Ile platform potrzebujesz?

Aby odpowiedzieć na to pytanie, powinieneś najpierw określić, kim są Twoi potencjalni użytkownicy i jak Twój program będzie używany. To pytanie zależy od tego, gdzie wdrażasz swoją aplikację.

Jeśli tworzysz ogólne oprogramowanie komputerowe w 2014 roku, Microsoft Windows może być najważniejszą platformą. Pamiętaj, że macOS i/lub Linux zyskują na popularności i mogą być ważnym celem dla Twojej aplikacji.

Popularność różnych systemów operacyjnych na komputery stacjonarne różni się w zależności od kraju, rodzaju używanego oprogramowania i grupy docelowej; nie ma ogólnej zasady. Na przykład macOS jest dość popularny w Ameryce Północnej i Europie Zachodniej, podczas gdy w Ameryce Południowej macOS ogranicza się głównie do pracy z wideo i dźwiękiem.

W wielu projektach kontraktowych odpowiednia jest tylko jedna platforma. Free Pascal i Lazarus są w stanie pisać oprogramowanie ukierunkowane na konkretną platformę. Możesz na przykład uzyskać dostęp do pełnego interfejsu API Windows, aby napisać dobrze zintegrowany program Windows.

Jeśli tworzysz oprogramowanie, które będzie działać na serwerze sieciowym, powszechnie używana jest platforma uniksowa w jednym z jej różnych wariantów. Być może w tym przypadku jako platformy docelowe sens mają tylko Linux, Solaris, *BSD i inne Uniksy, chociaż możesz chcieć dodać do kompletu obsługę Windows.

Po rozwiązaniu wszelkich problemów międzyplatformowych w swoim projekcie, możesz w dużej mierze zignorować inne platformy, podobnie jak w przypadku programowania dla jednej platformy. Jednak w pewnym momencie będziesz musiał przetestować wdrażanie i uruchamianie programu na innych platformach. W tym celu pomocny będzie nieograniczony dostęp do maszyn z docelowymi systemami operacyjnymi. Jeśli nie chcesz mieć wielu fizycznych komputerów, sprawdź rozwiązania z podwójnym rozruchem lub maszyną wirtualną (VM), taką jak:

  • VMware Fusion for Mac - Systemie hosta, na którym musi być uruchomiony system Intel macOS (komercyjny/bezpłatny do użytku niekomercyjnego).
  • VMware Workstation Player - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjny/bezpłatny do użytku osobistego).
  • VMware Workstation Pro - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjna/bezpłatna wersja próbna).
  • Parallels Desktop for Mac - Na systemie hosta musi być uruchomiony system Intel macOS (komercyjna/bezpłatna wersja próbna). Uwaga: istnieje Podgląd Techniczny, który będzie działał na procesorach Apple M1 ARM64, i który będzie obsługiwał wersje ARM systemu Linux i Windows 10 Insider Preview.
  • VirtualBox - Na systemie hosta może działać Intel macOS, Windows, Linux lub Solaris (Open Source).

Niektóre z nich, np. Parallels na Macu, sprawiają, że instalacja stacjonarnego systemu operacyjnego Linux za pomocą jednego kliknięcia jest banalna.

Zobacz także: Małe maszyny wirtualne i Qemu i inne emulatory.

Programowanie międzyplatformowe

Praca z plikami i folderami

Podczas pracy z plikami i folderami ważne jest, aby używać niespecyficznych dla platformy ograniczników ścieżki i sekwencji końca wiersza. Oto lista zadeklarowanych stałych w Lazarusie, które powinny być używane podczas pracy z plikami i folderami.

  • PathSep, PathSeparator: separator ścieżek używany podczas dodawania wielu ścieżek razem (';', ...)
  • PathDelim, DirectorySeparator: separator katalogów dla każdej platformy ('/', '\', ...)
  • LineEnding: poprawna sekwencja znaków końca wiersza (#13#10 - CRLF, #10 - LF, ...)

Inną ważną rzeczą, na którą należy zwrócić uwagę, jest rozróżnianie wielkości liter w systemie plików. W systemie Windows w nazwach plików zwykle nie jest rozróżniana wielkość liter, podczas gdy na platformach uniksowych (np. Linux, FreeBSD) zwykle rozróżniana jest wielkość liter, ale nie w macOS, pomimo jego dziedzictwa uniksowego. Należy jednak pamiętać, że jeśli system plików EXT2, EXT3 itp. jest zamontowany w systemie Windows, rozróżniana jest wielkość liter. Podobnie system plików FAT zamontowany w systemie Linux nie powinien rozróżniać wielkości liter.

Szczególną uwagę należy zwrócić na NTFS, który nie rozróżnia wielkości liter, gdy jest używany w systemie Windows, ale rozróżnia wielkość liter, gdy jest montowany w systemach POSIX. Może to powodować różne problemy, w tym utratę plików, jeśli pliki o tych samych nazwach, lecz różnych wariantach, istnieją na partycji NTFS zamontowanej w systemie Windows. Programiści powinni rozważyć użycie niestandardowych funkcji do sprawdzania i zapobiegania tworzenia kilku plików o tych samych nazwach w systemie NTFS.

macOS domyślnie używa nazw plików bez uwzględniania wielkości liter. Może to być przyczyną irytujących błędów, więc każda przenośna aplikacja powinna konsekwentnie używać takich nazw plików.

Funkcje plikowe biblioteki RTL używają kodowania systemowego dla nazw plików. W starszych systemach Windows (95/98/Me) jest to jedna ze stron kodowych systemu Windows, w nowszych UTF-16, podczas gdy Linux, BSD i macOS zwykle używają UTF-8. Moduł FileUtil biblioteki LCL zawiera funkcje plikowe, które przyjmują łańcuchy UTF-8, podobnie jak reszta LCL.

// Funkcje AnsiToUTF8 i UTF8ToAnsi wymagają menedżera widestring pod Linuksem, BSD, macOS,
// ale zwykle te systemy operacyjne używają UTF-8 jako kodowania systemowego, więc widestringmanager
// nie jest potrzebny.
function NeedRTLAnsi: boolean;// true if system encoding is not UTF-8
procedure SetNeedRTLAnsi(NewValue: boolean);
function UTF8ToSys(const s: string): string;     // podobna do UTF8ToAnsi, ale nie jest już zależna od widestringmanager
function SysToUTF8(const s: string): string;     // podobna do AnsiToUTF8, ale nie jest już zależna od widestringmanager
function UTF8ToConsole(const s: string): string; // konwertuje ciąg znaków UTF8 na kodowanie konsoli (używane przez Write, WriteLn)

// operacje na plikach
function FileExistsUTF8(const Filename: string): boolean;
function FileAgeUTF8(const FileName: string): Longint;
function DirectoryExistsUTF8(const Directory: string): Boolean;
function ExpandFileNameUTF8(const FileName: string): string;
function ExpandUNCFileNameUTF8(const FileName: string): string;
function ExtractShortPathNameUTF8(Const FileName : String) : String;
function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint;
function FindNextUTF8(var Rslt: TSearchRec): Longint;
procedure FindCloseUTF8(var F: TSearchrec);
function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;
function FileGetAttrUTF8(const FileName: String): Longint;
function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;
function DeleteFileUTF8(const FileName: String): Boolean;
function RenameFileUTF8(const OldName, NewName: String): Boolean;
function FileSearchUTF8(const Name, DirList : String): String;
function FileIsReadOnlyUTF8(const FileName: String): Boolean;
function GetCurrentDirUTF8: String;
function SetCurrentDirUTF8(const NewDir: String): Boolean;
function CreateDirUTF8(const NewDir: String): Boolean;
function RemoveDirUTF8(const Dir: String): Boolean;
function ForceDirectoriesUTF8(const Dir: string): Boolean;

// środowisko
function ParamStrUTF8(Param: Integer): string;
function GetEnvironmentStringUTF8(Index: Integer): string;
function GetEnvironmentVariableUTF8(const EnvVar: string): String;
function GetAppConfigDirUTF8(Global: Boolean): string;

// inne
function SysErrorMessageUTF8(ErrorCode: Integer): String;

Puste nazwy plików i podwójne separatory ścieżki

Istnieją pewne różnice w obsłudze nazw plików/katalogów w systemie Windows w porównaniu z systemami Linux, Unix i Unix.

  • Windows zezwala na puste nazwy plików. Dlatego FileExistsUTF8('..\') sprawdza w systemie Windows w katalogu nadrzędnym, czy istnieje plik bez nazwy.
  • W systemach Linux/Unix/Uniksopodobnych do katalogu mapowany jest pusty plik, a katalogi są traktowane jako pliki. Oznacza to, że FileExistsUTF8('../') pod Uniksem sprawdza istnienie katalogu nadrzędnego, co zwykle daje prawdę.

Podwójne separatory ścieżki w nazwach plików są również traktowane inaczej:

  • Windows: 'C:\' to nie to samo co 'C:\\'
  • Uniksy: ścieżka '/usr//' jest taka sama jak '/usr/'. Jeśli '/usr' jest katalogiem, to nawet wszystkie trzy zapisy są takie same.

Jest to ważne przy łączeniu nazw plików. Na przykład:

FullFilename:=FilePath+PathDelim+ShortFilename; // może skutkować dwoma znakami PathDelims, które dają różne wyniki pod Windows i Linux
FullFilename:=AppendPathDelim(FilePath) + ShortFilename; // tworzy tylko jeden znak PathDelim
FullFilename:=TrimFilename(FilePath+PathDelim+ShortFilename); // tworzy tylko jeden znak PathDelim i czyści ścieżkę

Funkcja TrimFilename zastępuje podwójne separatory ścieżek pojedynczymi jedynkami i skraca ścieżki typu '..'. Na przykład /usr//lib/../src jest przekształcony do postaci /usr/src.

Jeśli chcesz wiedzieć, czy katalog istnieje, użyj DirectoryExistsUTF8.

Innym częstym zadaniem jest sprawdzenie, czy istnieje ścieżka w nazwie pliku. Ścieżkę można uzyskać za pomocą ExtractFilePath, ale będzie ona zawierać separator ścieżki.

  • W systemie uniksowym możesz po prostu użyć FileExistsUTF8 na ścieżce. Na przykład FileExistsUTF8('/home/user/') zwróci true, jeśli katalog /home/user istnieje.
  • W systemie Windows musisz użyć funkcji DirectoryExistsUTF8, ale wcześniej musisz usunąć separator ścieżki, na przykład za pomocą funkcji ChompPathDelim.

W systemach uniksowych katalogiem głównym jest „/”, a użycie funkcji ChompPathDelim utworzy pusty ciąg. Funkcja DirPathExists działa jak funkcja DirectoryExistsUTF8, ale przycina podaną ścieżkę.

Zauważ, że Unix/Linux używa symbolu „~” (tylda) oznaczającego katalog domowy, np. „/home/jan/” dla użytkownika zwanego Jan. Tak więc „~/myapp/myfile” i „/home/jan/myapp/myfile” są identyczne w wierszu poleceń i skryptach. Jednak tylda nie jest automatycznie rozwijana przez Lazarusa. Aby uzyskać pełną ścieżkę, konieczne jest użycie ExpandFileNameUTF8('~/myapp/myfile').

Kodowanie tekstu

Pliki tekstowe są często kodowane w bieżącym kodowaniu systemowym. W starszych systemach Windows jest to zwykle jedna ze stron kodowych systemu Windows, a w nowszych UTF-16, podczas gdy Linux, BSD i macOS zwykle używają UTF-8. Nie ma zasady, która na 100% da odpowiedź, jakiego kodowania używa plik tekstowy. Moduł LCL lconvencoding ma funkcję do odgadywania kodowania:

function GuessEncoding(const s: string): string;
function GetDefaultTextEncoding: string;

oraz zawiera funkcje do konwersji z jednego kodowania na inne:

function ConvertEncoding(const s, FromEncoding, ToEncoding: string): string;

function UTF8BOMToUTF8(const s: string): string; // UTF8 z BOM
function ISO_8859_1ToUTF8(const s: string): string; // Europa Środkowa
function CP1250ToUTF8(const s: string): string; // Europa Środkowa
function CP1251ToUTF8(const s: string): string; // cyrylica
function CP1252ToUTF8(const s: string): string; // Latin-1 (Europa Zachodnia)
...
function UTF8ToUTF8BOM(const s: string): string; // UTF8 z BOM
function UTF8ToISO_8859_1(const s: string): string; // Europa Środkowa
function UTF8ToCP1250(const s: string): string; // Europa Środkowa
function UTF8ToCP1251(const s: string): string; // cyrylica
function UTF8ToCP1252(const s: string): string; // Latin-1 (Europa Zachodnia)
...

Na przykład, aby załadować plik tekstowy i przekonwertować go na UTF-8, możesz użyć:

var
  sl: TStringList;
  OriginalText: String;
  TextAsUTF8: String;
begin
  sl:=TStringList.Create;
  try
    sl.LoadFromFile('jakis_tekst.txt'); // uwaga: zmienia to zakończenia linii na systemowe zakończenia linii
    OriginalText:=sl.Text;
    TextAsUTF8:=ConvertEncoding(OriginalText,GuessEncoding(OriginalText),EncodingUTF8);
    ...
  finally
    sl.Free;
  end;
end;

Aby zapisać plik tekstowy w kodowaniu systemowym, możesz użyć:

sl.Text:=ConvertEncoding(TextAsUTF8,EncodingUTF8,GetDefaultTextEncoding);
sl.SaveToFile('jakis_tekst.txt');

Pliki konfiguracyjne

Możesz użyć funkcji GetAppConfigDir z modułu SysUtils, aby uzyskać odpowiednie miejsce do przechowywania plików konfiguracyjnych w innym systemie. Funkcja ma jeden parametr o nazwie Global. Jeśli ma wartość True, zwracany katalog jest katalogiem globalnym, tj. ważnym dla wszystkich użytkowników w systemie. Jeśli parametr Global ma wartość false, katalog jest specyficzny dla użytkownika, który wykonuje program. W systemach, które nie obsługują środowisk wielu użytkowników, te dwa katalogi mogą być takie same.

Istnieje również funkcja GetAppConfigFile, która zwróci odpowiednią nazwę dla pliku konfiguracyjnego aplikacji. Możesz jej użyć w ten sposób:

ConfigFilePath := GetAppConfigFile(False);

Poniżej znajdują się przykłady funkcji wypisujące domyślne ścieżki w różnych systemach:

program project1;

{$mode objfpc}{$H+}

uses
  SysUtils;

begin
  WriteLn(GetAppConfigDir(True));
  WriteLn(GetAppConfigDir(False));
  WriteLn(GetAppConfigFile(True));
  WriteLn(GetAppConfigFile(False));
end.

Możesz zauważyć, że w systemie Linux globalne pliki konfiguracyjne przechowywane są w katalogu /etc, a lokalne w ukrytym katalogu w katalogu domowym użytkownika. Katalogi, których nazwa zaczyna się od kropki (.) są ukryte w systemach operacyjnych UNIX i podobnych do UNIX. Możesz utworzyć katalog w lokalizacji zwróconej przez GetAppConfigDir, a następnie przechowywać tam pliki konfiguracyjne.

Note-icon.png

Uwaga: Zwykli użytkownicy nie mogą pisać do katalogu /etc. Mogą to zrobić tylko użytkownicy z uprawnieniami administratora.

Zauważ, że przed FPC 2.2.4 funkcja korzystała z katalogu, w którym aplikacja przechowywała globalne konfiguracje systemu Windows.

Dane wyjściowe w systemie Windows 98 z FPC 2.2.0:

C:\Program Files\PROJECT1
C:\Windows\Local Settings\Application Data\PROJECT1
C:\Program Files\PROJECT1\PROJECT1.cfg
C:\Windows\Local Settings\Application Data\PROJECT1\PROJECT1.cfg

Dane wyjściowe w systemie Windows XP z FPC 3.0.4:

C:\Documents and Settings\All Users\Application Data\project1\
C:\Documents and Settings\user\Local Settings\Application Data\project1\
C:\Documents and Settings\All Users\Application Data\project1\project1.cfg
C:\Documents and Settings\user\Local Settings\Application Data\project1\project1.cfg

Dane wyjściowe w systemach Windows 7 i Windows 10 z FPC 3.0.4:

C:\ProgramData\project1\
C:\Users\user\AppData\Local\project1\
C:\ProgramData\project1\project1.cfg
C:\Users\user\AppData\Local\project1\project1.cfg

Dane wyjściowe w systemie macOS 10.14.5 z FPC 3.0.4 (naruszają Wytyczne Apple — zobacz poniżej, aby poznać prawidłowe lokalizacje plików w systemie macOS):

/etc/project1/
/Users/user/.config/project1/
/etc/project1.cfg
/Users/user/.config/project1.cfg

Dane wyjściowe na FreeBSD 12.1 z FPC 3.0.4:

/etc/project1/
/home/user/.config/project1/
/etc/project1.cfg
/home/user/.config/project1.cfg

Obserwator może zauważyć różnicę między danymi wyjściowymi systemów operacyjnych Windows i innych niż Windows — dane wyjściowe systemu Windows dla WriteLn(GetAppConfigFile(True)); globalne ścieżki konfiguracji zawierają podkatalog projektu, ale inne systemy operacyjne nie. Aby uzyskać te same wyniki dla systemów operacyjnych innych niż Windows, należy dołączyć dodatkowy parametr logiczny: WriteLn(GetAppConfigFile(True,True));.

Note-icon.png

Uwaga: Użycie UPX zakłóca korzystanie z funkcji GetAppConfigDir i GetAppConfigFile.

macOS

W większości przypadków pliki konfiguracyjne to pliki preferencji, które w systemie macOS powinny być plikami XML z rozszerzeniem „.plist” i znajdować się w katalogu /Library/Preferences lub ~/Library/Preferences z nazwami pobranymi z pola „Identyfikator pakietu” w pliku Info.plist pakietu aplikacji. Używanie plików .config w katalogu użytkownika jest naruszeniem wytycznych programistycznych Apple. Zapoznaj się z artykułem Lokalizowanie obsługi aplikacji macOS, foldery preferencji, aby zapoznać się z kodem, który obsługuje to w sposób zgodny z Apple.

Pliki danych i zasobów

Bardzo częstym pytaniem jest, gdzie przechowywać pliki danych, których może potrzebować aplikacja, takie jak obrazy, muzyka, pliki XML, pliki bazy danych, pliki pomocy itp. Niestety nie ma funkcji wieloplatformowej, aby uzyskać najlepszą lokalizację do wyszukiwania plików danych. Rozwiązaniem jest implementacja w inny sposób na każdej platformie przy użyciu IFDEF.

Windows

W systemie Windows dane aplikacji, które modyfikuje program, nie powinny być umieszczane w katalogu aplikacji (np. C:\Program Files\), ale w określonej lokalizacji. System Windows Vista i nowsze aktywnie to wymuszają (użytkownicy mają dostęp tylko do zapisu w tych katalogach podczas korzystania z funkcji podnoszenia uprawnień lub wyłączania kontroli konta użytkownika), ale używają mechanizmu przekierowywania folderów, aby uwzględnić starsze, błędnie zaprogramowane aplikacje. Samo odczytywanie, a nie pisanie, danych z katalogów aplikacji nadal działa, ale nie jest to zalecane.

W skrócie: użyj takiego folderu:

    OpDirLocal:= GetEnvironmentVariableUTF8('appdata')+'\MyAppName';

Zobacz: Wskazówki dotyczące programowania w systemie Windows — uzyskiwanie specjalnych folderów

Unix/Linux

W większości systemów Unix (takich jak Linux, FreeBSD, OpenBSD, Solaris, ale nie macOS) pliki danych aplikacji znajdują się w stałej lokalizacji, która może wyglądać tak: /usr/local/share/nazwa_aplikacji lub /opt/nazwa_aplikacji.

Dane aplikacji, do których aplikacja musi zapisać, często są przechowywane w miejscach takich jak /usr/local/var/nazwa_aplikacji, /usr/local/share/nazwa_aplikacji lub /usr/local/nazwa_aplikacji, z odpowiednimi uprawnieniami.

Pliki pomocy (inaczej strony podręcznika) powinny być przechowywane w /usr/local/man/man[numer odpowiedniej sekcji podręcznika]/nazwa_aplikacji>, z odpowiednimi uprawnieniami. Zauważ, że niektóre sekcje podręcznika FreeBSD i Linuksa różnią się lub nie istnieją.

Pliki konfiguracji/danych do odczytu/zapisu specyficzne dla użytkownika będą zwykle przechowywane gdzieś w katalogu domowym użytkownika (np. w ~/.config/<nazwa programu>). Zapoznaj się z powyższymi plikami konfiguracyjnymi.

macOS

macOS jest wyjątkiem wśród systemów operacyjnych UNIX. Aplikacja jest publikowana w pakiecie (katalog z rozszerzeniem „.app”), który jest traktowany przez menedżera plików Finder jako plik (w Terminalu można użyć „cd path/myapp.app” lub w Finderze prawym przyciskiem myszy na aplikacji i wybierz „Show Package Contents” („Pokaż zawartość pakietu”). Twoje pliki zasobów powinny znajdować się wewnątrz pakietu. Jeśli pakiet to „path/MojaAplikacja.app”, to:

  • plik wykonywalny to "path/MojaAplikacja.app/Contents/MacOS/myapp"
  • katalog zasobów to "path/MojaAplikacja.app/Contents/Resources"

Dane i pliki zasobów dostarczane przez aplikację powinny być zazwyczaj przechowywane w katalogu Resources pakietu aplikacji. Aby zapoznać się z kodem, który obsługuje to w sposób zgodny z Apple, zobacz artykuł Lokalizowanie katalogu zasobów aplikacji systemu macOS.

Pliki danych aplikacji wygenerowane przez użytkownika powinny być przechowywane w katalogu użytkownika „~/Library/Application Support”. Aby poznać kod, który obsługuje to w sposób zgodny z Apple, zapoznaj się z artykułem Lokalizowanie obsługi aplikacji macOS, foldery preferencji.

Warning-icon.png

Ostrzeżenie: Nigdy nie używaj paramStr(0) ani żadnej funkcji, która go używa, na żadnej platformie UNIX do określenia lokalizacji pliku wykonywalnego, ponieważ jest to konwencja DOS-Windows-OS/2 i ma kilka problemów koncepcyjnych, których nie można rozwiązać za pomocą emulacji na innych platformach. Jedyną rzeczą, którą paramStr(0) gwarantuje na platformach UNIX jest nazwa, pod którą program został uruchomiony. Nie ma gwarancji, że katalog, w którym się znajduje, oraz nazwa rzeczywistego pliku binarnego (w przypadku, gdy został uruchomiony przy użyciu dowiązania symbolicznego) będą dostępne za pośrednictwem paramStr(0). W przypadku systemu macOS można niezawodnie zlokalizować katalog pakietu aplikacji przy użyciu kodu natywnego opisanego w tym artykule.

32/64 bit

Wykrywanie wersji bitowej systemu w czasie wykonywania

Chociaż możesz kontrolować, czy kompilujesz dla systemu 32 lub 64-bit za pomocą definicji kompilatora, czasami chcesz wiedzieć, jaka jest bitowość systemu operacyjnego. Na przykład, jeśli używasz 32-bitowego programu Lazarus w 64-bitowym systemie Windows, możesz chcieć uruchomić zewnętrzny program w katalogu 32-bitowych plików programu lub możesz chcieć przekazać użytkownikom inne informacje: Potrzebuję tego w moim instalatorze Lazarusa LazUpdater oferujący użytkownikowi wybór 32- i 64-bitowych kompilatorów. Przykład kodu: Wykryj Windows x32-x64.

Wykrywanie wersji bitowej zewnętrznej biblioteki przed jej załadowaniem

Kiedy chcesz załadować funkcje z biblioteki dynamicznej do twojego programu, musi ona mieć taką samą wersję bitową jak twoja aplikacja. W 64-bitowym systemie Windows aplikacja może być 32-bitowa lub 64-bitowa, a w systemie mogą znajdować się biblioteki 32-bitowe i 64-bitowe. Więc możesz chcieć sprawdzić, czy wersja bitowa biblioteki dll jest taka sama jak twojej aplikacji przed dynamicznym załadowaniem dll. Oto funkcja testująca wersję bitową dll (opublikowana na forum przez GetMem) (komentarze zostały przetłumaczone):

uses {..., } JwaWindows;

function GetPEType(const APath: WideString): Byte;
const
  PE_UNKNOWN = 0; //jeśli plik nie jest poprawną biblioteką dll, zwracane jest 0
 // PE_16BIT   = 1; // nieobsługiwane przez tę funkcję
  PE_32BIT   = 2;
  PE_64BIT   = 3;
var
  hFile, hFileMap: THandle;
  PMapView: Pointer;
  PIDH: PImageDosHeader;
  PINTH: PImageNtHeaders;
  Base: Pointer;
begin
  Result := PE_UNKNOWN;
 
  hFile := CreateFileW(PWideChar(APath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if hFile = INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hFile);
    Exit;
  end;
 
  hFileMap  := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
  if hFileMap = 0 then
  begin
    CloseHandle(hFile);
    CloseHandle(hFileMap);
    Exit;
  end;
 
  PMapView := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  if PMapView = nil then
  begin
    CloseHandle(hFile);
    CloseHandle(hFileMap);
    Exit;
  end;
 
  PIDH := PImageDosHeader(PMapView);
  if PIDH^.e_magic <> IMAGE_DOS_SIGNATURE then
  begin
    CloseHandle(hFile);
    CloseHandle(hFileMap);
    UnmapViewOfFile(PMapView);
    Exit;
  end;
 
  Base := PIDH;
  PINTH := PIMAGENTHEADERS(Base + LongWord(PIDH^.e_lfanew));
  if PINTH^.Signature = IMAGE_NT_SIGNATURE then
  begin
    case PINTH^.OptionalHeader.Magic of
      $10b: Result := PE_32BIT;
      $20b: Result := PE_64BIT
    end;
  end;
 
  CloseHandle(hFile);
  CloseHandle(hFileMap);
  UnmapViewOfFile(PMapView);
end;

//Teraz, jeśli skompilujesz swoją aplikację dla 32-bitowych i 64-bitowych wersji Windows,
//możesz sprawdzić, czy wersja bitowa dll jest taka sama jak w Twojej aplikacji:
function IsCorrectBitness(const APath: WideString): Boolean;
begin  
  {$ifdef CPU32}
    Result := GetPEType(APath) = 2; //aplikacja jest kompilowana jako 32-bitowa, pytamy czy GetPeType zwraca 2
  {$endif}
  {$ifdef CPU64}
    Result := GetPEType(APath) = 3; //aplikacja jest kompilowana jako 64-bitowa, pytamy czy GetPeType zwraca 3
  {$endif}
end;

Typy wskaźników / liczb całkowitych

Wskaźniki pod architekturą 64-bitową zajmują 8 bajtów zamiast 4 na 32-bitowej. Typ 'Integer' pozostaje 32-bitowy na wszystkich platformach, aby zapewnić zgodność. Oznacza to, że nie możesz rzutować wskaźników na typ Integer i z powrotem.

FPC definiuje w tym celu dwa typy: PtrInt i PtrUInt. PtrInt to 32-bitowa liczba całkowita ze znakiem na platformach 32-bitowych i 64-bitowa liczba całkowita ze znakiem na platformach 64-bitowych. To samo dla PtrUInt, ale dla liczb całkowitych bez znaku.

Użyj dla kodu, który powinien działać z Delphi i FPC:

 {$IFNDEF FPC}
 type
   PtrInt = integer;
   PtrUInt = cardinal;
 {$ENDIF}

Zamień wszystkie rzutowania wskaźnika Integer(SomePointerOrObject) na PtrInt(SomePointerOrObject).

Kolejność bajtów

Platformy Intela są little endian, co oznacza, że ​​najmniej znaczący bajt jest na pierwszym miejscu. Na przykład dwa bajty słowa $1234 są przechowywane kolejno jako $34 $12 w systemach little endian. W systemach typu big endian, takich jak powerpc, dwa bajty słowa $1234 są przechowywane kolejno jako $12 $34. Różnica jest istotna przy odczytywaniu plików utworzonych na innych systemach.

Użyj dla kodu, który powinien działać na obu systemach:

{$IFDEF ENDIAN_BIG}
...
{$ELSE}
...
{$ENDIF}

Przeciwieństwo dla ENDIAN_BIG to ENDIAN_LITTLE.

Moduł system zapewnia wiele funkcji konwertujących endian, takich jak SwapEndian, BEtoN (big endian do bieżącego endian), LEtoN (little endian do bieżącego endian), NtoBE (bieżący endian do big endian) i NtoLE (bieżący endian do little endian).

Libc i inne jednostki specjalne

Unikaj starszych modułów, takich jak „oldlinux” i „libc”, które nie są obsługiwane poza linux/i386.

Asembler

Unikaj używania asemblera.

Dyrektywy kompilatora

{$ifdef CPU32}
...tutaj napisz kod dla procesorów 32-bitowych
{$ENDIF}
{$ifdef CPU64}
...tutaj napisz kod dla procesorów 64-bitowych
{$ENDIF}

Projekty, pakiety i ścieżki wyszukiwania

Lazarus projects and packages are designed for multi platforms. Normally you can simply copy the project and the required packages to another machine and compile them there. You don't need to create one project per platform. Projekty i pakiety Lazarusa są przeznaczone dla wielu platform. Zwykle możesz po prostu skopiować projekt i wymagane pakiety na inny komputer i tam je skompilować. Nie musisz tworzyć osobnego projektu dla każdej platformy.

Kilka rad, jak to osiągnąć.

Kompilator tworzy dla każdego modułu plik ppu o tej samej nazwie. Ten plik ppu może być używany przez inne projekty i pakiety. Pliki źródłowe modułu (np. unit1.pas) nie powinny być udostępniane. Po prostu daj kompilatorowi katalog wyjściowy modułu, w którym ma tworzyć pliki ppu. IDE robi to domyślnie, więc nie ma tu nic do roboty.

Każdy plik modułu musi być częścią jednego projektu lub pakietu. Jeśli plik modułu jest używany tylko w jednym projekcie, dodaj go do tego projektu. W przeciwnym razie dodaj go do pakietu. Jeśli jeszcze nie utworzyłeś pakietu dla swoich modułów współdzielonych, zobacz tutaj: Tworzenie pakietu dla wspólnych modułów.

Każdy projekt i każdy pakiet powinien mieć oddzielne katalogi - nie powinny one współdzielić katalogów. W przeciwnym razie musisz być ekspertem w dziedzinie ścieżek wyszukiwania kompilatora. Jeśli nie jesteś ekspertem lub jeśli inne osoby, które mogą korzystać z Twojego projektu/pakietu, nie są ekspertami: nie twórz wspólnego katalogu dla projektów i pakietów.

Moduły zależne od platformy

Na przykład moduł wintricks.pas powinien być używany tylko w systemie Windows. W sekcji uses użyj:

uses
  Classes, SysUtils
  {$IFDEF Windows}
  ,WinTricks
  {$ENDIF}
  ;

Jeśli moduł jest częścią pakietu, należy również wybrać ten moduł w edytorze pakietów i odznaczyć pole wyboru Use unit.

Zobacz także Moduły zależne od platformy

Ścieżki wyszukiwania specyficzne dla platformy

Kiedy wybierasz kilka platform i masz bezpośredni dostęp do systemu operacyjnego, szybko zmęczysz się niekończącymi się konstrukcjami IFDEF. Jednym z rozwiązań często stosowanych w źródłach FPC i Lazarus jest użycie plików dołączanych (include files). Utwórz jeden podkatalog na każdą docelową platformę. Na przykład win32, linux, bsd, darwin. Umieść w każdym katalogu plik dołączany o tej samej nazwie. Następnie użyj makra w ścieżce include. Moduł może używać normalnej dyrektywy include.

Przykład jednego pliku include dla każdego zestawu widżetów LCL:

Utwórz jeden plik dla każdego zestawu widżetów, który chcesz obsługiwać:

win32/example.inc
gtk/example.inc
gtk2/example.inc
carbon/example.inc

Nie musisz dodawać plików do pakietu lub projektu. Dodaj ścieżkę wyszukiwania include $(LCLWidgetType) do opcji kompilatora pakietu lub projektu.

W swoim module użyj dyrektywy: {$I example.inc}

Oto kilka przydatnych makr i typowych wartości:

  • LCLWidgetType: win32, gtk, gtk2, qt, carbon, fpgui, nogui
  • TargetOS: linux, win32, win64, wince, freebsd, netbsd, openbsd, darwin (many more)
  • TargetCPU: i386, x86_64, arm, powerpc, sparc
  • SrcOS: win, unix

Do używania zmiennych środowiskowych można użyć makra $Env().

I oczywiście możesz używać ich kombinacji. Na przykład LCL wykorzystuje:

$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS);$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType)

Zobacz tutaj pełną listę makr: Makra IDE w ścieżkach i nazwach plików.

Ścieżki wyszukiwania specyficzne dla maszyny/użytkownika

Na przykład masz dwa komputery z systemem Windows, stan i oliver. W komputerze 'stan twoje moduły znajdują się w C:\units, a na oliver w D:\path. Moduły należą do pakietu SharedStuff, który jest w pliku C:\units\sharedstuff.lpk na stan i i w pliku D:\path\sharedstuff.lpk na oliver. Po otwarciu pliku lpk w IDE lub przez lazbuild, ścieżka jest automatycznie zapisywana w jego plikach konfiguracyjnych (packagefiles.xml). Podczas kompilowania projektu, który wymaga pakietu SharedStuff, IDE i lazbuild wiedzą, gdzie on jest. Więc nie jest potrzebna konfiguracja.

Jeśli chcesz wdrożyć pakiet na wielu maszynach lub dla wszystkich użytkowników maszyny (np. basen dla studentów), możesz dodać plik lpl w katalogu źródłowym lazarusa. Zobacz katalog Lazarusa packager/globallinks, aby zapoznać się z przykładami.

Różnice regionalne

Niektóre funkcje z Free Pascal, takie jak StrToFloat, zachowują się różnie w zależności od ustawień bieżącego regionu. Na przykład w USA separatorem dziesiętnym jest zwykle „.”, ale w wielu krajach Europy (w tym w Polsce) i Ameryki Południowej jest to „,”. Może to stanowić problem, ponieważ czasami pożądane jest, aby te funkcje zachowywały się w ustalony sposób, niezależnie od ustawień regionalnych. Przykładem jest format pliku z kropkami dziesiętnymi, które zawsze należy interpretować w ten sam sposób.

Następne sekcje wyjaśniają, jak to zrobić.

macOS

Zapoznaj się z artykułem Ustawienia regionalne dla systemu macOS, aby uzyskać szczegółowe informacje na temat ustawiania języka w systemie macOS.

StrToFloat

Nowy zestaw ustawień formatu, który ustawia stały separator dziesiętny, można utworzyć za pomocą następującego kodu:

// w pliku projektu .lpr
uses
...
{$IFDEF UNIX}
clocale 
{ wymagane w systemie Linux/Unix do obsługi ustawień formatów. Powinien być jednym z pierwszych (prawdopodobnie po cthreads?}
{$ENDIF}

and:

// w twoim kodzie:
var
  FPointSeparator, FCommaSeparator: TFormatSettings;
begin
  // Format settings to convert a string to a float
  // Ustawienia formatu, aby przekonwertować ciąg string na liczbę zmiennoprzecinkowąq
  FPointSeparator := DefaultFormatSettings;
  FPointSeparator.DecimalSeparator := '.';
  FPointSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
  FCommaSeparator := DefaultFormatSettings;
  FCommaSeparator.DecimalSeparator := ',';
  FCommaSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy

Później możesz użyć tych ustawień formatu podczas wywoływania StrToFloat, na przykład:

// Ta funkcja działa jak StrToFloat, ale po prostu próbuje dwóch możliwych separatorów dziesiętnych
// Pozwoli to uniknąć wyjątku, gdy format ciągu string nie pasuje do ustawień regionalnych
function AnSemantico.StringToFloat(AStr: string): Double;
begin
  if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator)
  else Result := StrToFloat(AStr, FCommaSeparator);
end;

Gtk2 i maskowanie wyjątków FPU

Biblioteka Gtk2 zmienia domyślną wartość maski wyjątków FPU (koprocesor - jednostka zmiennoprzecinkowa). Konsekwencją tego jest to, że niektóre wyjątki zmiennoprzecinkowe nie są zgłaszane, jeśli aplikacja korzysta z biblioteki Gtk2. Oznacza to, że jeśli na przykład tworzysz aplikację LCL w systemie Windows z zestawem widżetów win32/64 (który jest domyślnym systemem Windows) i planujesz kompilację dla systemu Linux (gdzie Gtk2 jest domyślnym zestawem widżetów), powinieneś pamiętać o tych niezgodnościach.

Po tym zgłoszeniu na forum i odpowiedziach na ten raport o błędzie stało się jasne, że nic nie można z tym zrobić, więc musimy wiedzieć, czym właściwie są te różnice.

Dlatego zróbmy test:

uses
  ..., math,...

{...}

var
  FPUException: TFPUException;
  FPUExceptionMask: TFPUExceptionMask;
begin
  FPUExceptionMask := GetExceptionMask;
  for FPUException := Low(TFPUException) to High(TFPUException) do begin
    write(FPUException, ' - ');
    if not (FPUException in FPUExceptionMask) then
      write('not ');

    writeln('masked!');
  end;
  readln;
end.

Nasz prosty program otrzyma domyślne wartości FPC:

 exInvalidOp - not masked!
 exDenormalized - masked!
 exZeroDivide - not masked!
 exOverflow - not masked!
 exUnderflow - masked!
 exPrecision - masked!

Jednak w przypadku Gtk2 tylko exOverflow nie jest maskowany.

Konsekwencją jest to, że wyjątki EInvalidOp i EZeroDivide nie są zgłaszane, jeśli aplikacja łączy się z biblioteką Gtk2! Zwykle dzielenie wartości niezerowej przez zero powoduje wyjątek EZeroDivide, a dzielenie zera przez zero powoduje zwiększenie EInvalidOp. Na przykład taki kod:

var
  X, A, B: Double;
// ...

try
  X := A / B;
  // blok kodu 1
except   
  // blok kodu 2
end;
// ...

przyjmie inny kierunek po skompilowaniu w aplikacji z zestawem widżetów Gtk2. W zestawie widżetów win, gdy B jest równe zero, zostanie zgłoszony wyjątek (EZeroDivide lub EInvalidOp, w zależności od tego, czy A jest zerem) i zostanie wykonany „blok kodu 2”. Na Gtk2 X staje się Infinity, NegInfinity lub NaN i „blok kodu 1” zostanie wykonany.

Możemy wymyślić różne sposoby przezwyciężenia tej niespójności. W większości przypadków możesz po prostu sprawdzić, czy B jest równe zero i nie próbować dzielić w takim przypadku. Czasami jednak będziesz potrzebować innego podejścia. Spójrz więc na następujące przykłady:

uses
  ..., math,...

//...
var
  X, A, B: Double;
  Ind: Boolean;
// ...
try
  X := A / B;
  Ind := IsInfinite(X) or IsNan(X); // z gtk2 wpadamy tutaj
except   
  Ind := True; // w Windows wpadamy tutaj, gdy B równa się zero
end;
if Ind then begin
  // blok kodu 2
end else begin
  // blok kodu 1
end;
// ...

Lub:

uses
  ..., math,...

//...
var
  X, A, B: Double;
  FPUExceptionMask: TFPUExceptionMask;
// ...

try
  FPUExceptionMask := GetExceptionMask;
  SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]); // niemaskowane
  try
    X := A / B;
  finally
    SetExceptionMask(FPUExceptionMask); // natychmiast zwróć poprzednie maskowanie, nie możemy pozwolić, aby wewnętrzne elementy Gtk2 były wywoływane bez maski
  end;
  // blok kodu 1
except   
  // blok kodu 2
end;
// ...

Bądź ostrożny, nie rób czegoś takiego (wywołanie LCL z wciąż zdjętą maską):

try
  FPUExceptionMask := GetExceptionMask;
  SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
  try
    Edit1.Text := FloatToStr(A / B); // NIE! Ustawienie tekstu Edit sprowadza się do wewnętrznych widżetów, a API Gtk2 nie może być wywoływane bez maski!
  finally
    SetExceptionMask(FPUExceptionMask);
  end;
  // blok kodu 1
except   
  // blok kodu 2
end;
// ...

Ale użyj zmiennej pomocniczej:

try
  FPUExceptionMask := GetExceptionMask;
  SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
  try
    X := A / B; // Najpierw ustawiamy zmienną pomocniczą X
  finally
    SetExceptionMask(FPUExceptionMask);
  end;
  Edit1.Text := FloatToStr(X); // Teraz możemy ustawić tekst w Edit.
  // blok kodu 1
except   
  // blok kodu 2
end;
// ...

We wszystkich sytuacjach podczas tworzenia aplikacji LCL najważniejsze jest, aby o tym wiedzieć i pamiętać, że niektóre operacje zmiennoprzecinkowe mogą przebiegać w inny sposób z różnymi zestawami widżetów. Następnie możesz wymyślić odpowiedni sposób na obejście tego, ale nie powinno to pozostać niezauważone.

Problemy przy przejściu z systemu Windows do *nix itp.

W tym miejscu opisano problemy specyficzne dla systemów Linux, macOS, Android i innych Uniksów. Nie wszystkie tematy mogą dotyczyć wszystkich platform.

W Uniksie nie ma „katalogu aplikacji”

Wielu programistów jest przyzwyczajonych do wywoływania ExtractFilePath(ParamStr(0)) lub Application.ExeName w celu uzyskania lokalizacji pliku wykonywalnego, a następnie wyszukiwania plików niezbędnych do wykonania programu (obrazy, pliki XML, pliki bazy danych itp.) na podstawie lokalizacji pliku wykonywalnego. To jest złe na unixach. Ciąg w ParamStr(0) może zawierać katalog inny niż plik wykonywalny, a także różni się między różnymi programami powłoki (sh, bash, itp.).

Nawet jeśli Application.ExeName może w rzeczywistości znać katalog, w którym znajduje się plik wykonywalny, plik ten może być dowiązaniem symbolicznym, więc zamiast tego można uzyskać katalog dowiązania (w zależności od wersji jądra Linux można uzyskać katalog dowiązania lub samego programu binarnego).

Aby tego uniknąć, przeczytaj sekcje dotyczące plików konfiguracyjnych i plików danych.

Obycie się bez Windows COM Automation

W systemie Windows Automatyzacja COM jest potężnym sposobem nie tylko na zdalne manipulowanie innymi programami, ale także na umożliwienie innym programom manipulowania Twoim programem. Dzięki Delphi możesz uczynić swój program zarówno klientem COM Automation, jak i serwerem COM Automation, co oznacza, że ​​może on zarówno manipulować innymi programami, jak i być manipulowany przez inne programy. Aby zapoznać się z przykładami, zobacz Używanie automatyzacji COM do interakcji z pakietami OpenOffice i Microsoft Office.

alternatywa dla macOS

Niestety, COM Automation nie jest dostępna w systemach macOS i Linux. Można jednak symulować niektóre funkcje COM Automation w systemie macOS za pomocą AppleScript.

AppleScript jest pod pewnymi względami podobny do COM Automation. Na przykład możesz pisać skrypty, które manipulują innymi programami. Oto bardzo prosty przykład AppleScript, który uruchamia NeoOffice (wersja OpenOffice.org na Maca):

  tell application "NeoOffice"
    launch
  end tell

Aplikacja zaprojektowana do manipulowania przez AppleScript udostępnia „słownik” klas i poleceń, których można używać z aplikacją, podobnie jak klasy serwera Windows Automation. Jednak nawet aplikacje, takie jak NeoOffice, które nie udostępniają słownika, nadal będą odpowiadać na polecenia „launch” (uruchom), „activate” (aktywuj) i „quit” (wyjście). AppleScript można uruchomić z edytora skryptów macOS lub Findera, a nawet przekonwertować na aplikację, którą można upuścić do stacji dokującej, tak jak każdą aplikację. Możesz także uruchomić AppleScript ze swojego programu, jak w tym przykładzie:

  fpsystem('myscript.applescript');

Zakłada się, że skrypt znajduje się we wskazanym pliku. Możesz także uruchamiać skrypty w locie ze swojej aplikacji za pomocą polecenia macOS OsaScript:

  fpsystem('osascript -e '#39'tell application "NeoOffice"'#39 +
        ' -e '#39'launch'#39' -e '#39'end tell'#39);
        {Zwróć uwagę na użycie #39 jako pojedynczego cudzysłowu do parametrów}

Jednak te przykłady są tylko odpowiednikiem następującego polecenia Open (otwórz):

  fpsystem('open -a NeoOffice');

Podobnie w systemie macOS można emulować polecenia powłoki systemu Windows, aby uruchomić przeglądarkę internetową i uruchomić klienta poczty e-mail za pomocą:

  fpsystem('open -a safari "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');

i

  fpsystem('open -a mail "mailto:ss4200@invalid.org"');

co zakłada, dość bezpiecznie, że system macOS będzie miał zainstalowane aplikacje Safari i Mail. Oczywiście nigdy nie należy przyjmować takich założeń, a w przypadku dwóch poprzednich przykładów można po prostu polegać na systemie macOS, aby postępować właściwie i wybrać domyślną przeglądarkę internetową i klienta poczty e-mail użytkownika, jeśli zamiast tego użyjesz tych odmian:

  fpsystem('open "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');

i

  fpsystem('open "mailto:ss4200@invalid.org"');

Nie zapomnij dołączyć modułu Unix do klauzuli uses, jeśli używasz fpsystem lub shell (wymiennie).

Prawdziwą mocą AppleScript jest zdalne manipulowanie programami w celu tworzenia i otwierania dokumentów oraz automatyzacji innych czynności. To, ile możesz zrobić z programem, zależy od tego, jak obszerny jest jego słownik AppleScript (jeśli taki posiada). Na przykład programy Microsoft Office X nie są zbyt użyteczne z AppleScript, podczas gdy nowsze programy Office 2004 mają całkowicie przepisane słowniki AppleScript, które pod wieloma względami porównywalne są z tym, co jest dostępne za pośrednictwem serwerów Windows Office Automation.

Alternatywy dla Linuksa

Chociaż powłoki Linuksa obsługują zaawansowane skrypty wiersza poleceń, typ skryptów jest ograniczony do tego, co można przekazać do programu w wierszu poleceń. Nie ma jednego, zunifikowanego sposobu, aby uzyskać dostęp do wewnętrznych klas i poleceń programu w systemie Linux w taki sposób, w jaki są one dostępne, za pośrednictwem Windows COM Automation i macOS AppleScript. Jednak indywidualne środowiska graficzne (GNOME/KDE) i frameworki aplikacji często zapewniają takie metody komunikacji międzyprocesowej. W GNOME zobacz Komponenty Bonobo. KDE posiada framework KParts, DCOP. OpenOffice ma neutralne dla platformy API do zdalnego sterowania biurem (Google OpenOffice SDK) – chociaż prawdopodobnie, aby go używać, będziesz musiał napisać kod łączący w innym języku, który ma powiązania (takie jak Python). Ponadto niektóre aplikacje mają „tryby serwera” aktywowane przez specjalne opcje wiersza polecenia, które umożliwiają sterowanie nimi z innego procesu. Możliwe jest również (Borland zrobił to za pomocą przeglądarki dokumentów Kylix) „osadzenie” jednego okna aplikacji X najwyższego poziomu w innym za pomocą XReparentWindow (chyba).

Podobnie jak w przypadku systemu Windows, wiele programów dla systemów MacOS i Linux składa się z wielu plików bibliotek (rozszerzenia .dylib i .so). Czasami te biblioteki są zaprojektowane tak, abyś mógł ich używać również w programach, które piszesz. Chociaż może to być sposób na dodanie niektórych funkcji zewnętrznego programu do twojego programu, nie jest to tak naprawdę to samo, co uruchamianie i manipulowanie samym zewnętrznym programem. Zamiast tego twój program po prostu łączy się i używa biblioteki programu zewnętrznego, podobnie jak używałby dowolnej biblioteki programistycznej.

Alternatywy dla funkcji Windows API

Wiele programów systemu Windows intensywnie korzysta z interfejsu API systemu Windows. W aplikacjach wieloplatformowych funkcje Win API w module Windows nie powinny być używane lub powinny być zawarte w kompilacji warunkowej (np. {$IFDEF MSWINDOWS} ).

Na szczęście wiele z powszechnie używanych funkcji Windows API jest zaimplementowanych wieloplatformowo w module lclintf. Może to być rozwiązanie dla programów, które w dużym stopniu opierają się na API Windows, chociaż najlepszym rozwiązaniem jest zastąpienie tych wywołań prawdziwymi wieloplatformowymi komponentami z LCL. Na przykład można zastąpić wywołania funkcji malowania GDI za pomocą wywołania metod obiektu TCanvas.

Kody klawiszy

Na szczęście wykrywanie kodów klawiszy (np. w zdarzeniach KeyUp) jest przenośne: patrz Obsługa klawiszy LCL.

Instalowanie swojej aplikacji

Zobacz Wdrażanie swojej aplikacji.

Zobacz także

Linki zewnętrzne