Sign in Join
Wiki copytemporary

Multiplatform Programming Guide/pl: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Multiplatform Programming Guide/pl

OldNewLine
1+<div style="font-size:1.88em;margin:0.75em 0;">
2+
3+Przewodnik programowania wieloplatformowego
4+
5+</div>
6+
7+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]].
8+
9+Większość aplikacji LCL działa na wielu platformach bez dodatkowej pracy. Ta zasada nazywa się [[Write once compile anywhere/pl|„napisz raz, kompiluj wszędzie”]].
10+
11+## Wprowadzenie do programowania wieloplatformowego (międzyplatformowego)
12+
13+### Ile platform potrzebujesz?
14+
15+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ę.
16+
17+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.
18+
19+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.
20+
21+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.
22+
23+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.
24+
25+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:
26+
27+- [VMware Fusion for Mac](https://www.vmware.com/products/fusion.html) - Systemie hosta, na którym musi być uruchomiony system Intel macOS (komercyjny/bezpłatny do użytku niekomercyjnego).
28+- [VMware Workstation Player](https://www.vmware.com/products/workstation-player.html) - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjny/bezpłatny do użytku osobistego).
29+- [VMware Workstation Pro](https://www.vmware.com/products/workstation-pro.html) - System hosta z 64-bitowym systemem Windows lub 64-bitowym systemem Linux (komercyjna/bezpłatna wersja próbna).
30+- [Parallels Desktop for Mac](https://www.parallels.com/) - Na systemie hosta musi być uruchomiony system Intel macOS (komercyjna/bezpłatna wersja próbna). Uwaga: istnieje [Podgląd Techniczny](https://b2b.parallels.com/Apple-Silicon), 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](https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64).
31+- [VirtualBox](https://www.virtualbox.org/) - Na systemie hosta może działać Intel macOS, Windows, Linux lub Solaris (Open Source).
32+
33+Niektóre z nich, np. Parallels na Macu, sprawiają, że instalacja stacjonarnego systemu operacyjnego Linux za pomocą jednego kliknięcia jest banalna.
34+
35+**Zobacz także:** [[Small Virtual Machines|Małe maszyny wirtualne]] i [[Qemu and other emulators|Qemu i inne emulatory]].
36+
37+## Programowanie międzyplatformowe
38+
39+### Praca z plikami i folderami
40+
41+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.
42+
43+- **PathSep**, **PathSeparator**: separator ścieżek używany podczas dodawania wielu ścieżek razem (';', ...)
44+- **PathDelim**, **DirectorySeparator**: separator katalogów dla każdej platformy ('/', '\\', ...)
45+- **LineEnding**: poprawna sekwencja znaków końca wiersza (#13#10 - CRLF, \#10 - [[Line feed|LF]], ...)
46+
47+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.
48+
49+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.
50+
51+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.
52+
53+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.
54+
55+``` pascal
56+// Funkcje AnsiToUTF8 i UTF8ToAnsi wymagają menedżera widestring pod Linuksem, BSD, macOS,
57+// ale zwykle te systemy operacyjne używają UTF-8 jako kodowania systemowego, więc widestringmanager
58+// nie jest potrzebny.
59+function NeedRTLAnsi: boolean;// true if system encoding is not UTF-8
60+procedure SetNeedRTLAnsi(NewValue: boolean);
61+function UTF8ToSys(const s: string): string; // podobna do UTF8ToAnsi, ale nie jest już zależna od widestringmanager
62+function SysToUTF8(const s: string): string; // podobna do AnsiToUTF8, ale nie jest już zależna od widestringmanager
63+function UTF8ToConsole(const s: string): string; // konwertuje ciąg znaków UTF8 na kodowanie konsoli (używane przez Write, WriteLn)
64+
65+// operacje na plikach
66+function FileExistsUTF8(const Filename: string): boolean;
67+function FileAgeUTF8(const FileName: string): Longint;
68+function DirectoryExistsUTF8(const Directory: string): Boolean;
69+function ExpandFileNameUTF8(const FileName: string): string;
70+function ExpandUNCFileNameUTF8(const FileName: string): string;
71+function ExtractShortPathNameUTF8(Const FileName : String) : String;
72+function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint;
73+function FindNextUTF8(var Rslt: TSearchRec): Longint;
74+procedure FindCloseUTF8(var F: TSearchrec);
75+function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;
76+function FileGetAttrUTF8(const FileName: String): Longint;
77+function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;
78+function DeleteFileUTF8(const FileName: String): Boolean;
79+function RenameFileUTF8(const OldName, NewName: String): Boolean;
80+function FileSearchUTF8(const Name, DirList : String): String;
81+function FileIsReadOnlyUTF8(const FileName: String): Boolean;
82+function GetCurrentDirUTF8: String;
83+function SetCurrentDirUTF8(const NewDir: String): Boolean;
84+function CreateDirUTF8(const NewDir: String): Boolean;
85+function RemoveDirUTF8(const Dir: String): Boolean;
86+function ForceDirectoriesUTF8(const Dir: string): Boolean;
87+
88+// środowisko
89+function ParamStrUTF8(Param: Integer): string;
90+function GetEnvironmentStringUTF8(Index: Integer): string;
91+function GetEnvironmentVariableUTF8(const EnvVar: string): String;
92+function GetAppConfigDirUTF8(Global: Boolean): string;
93+
94+// inne
95+function SysErrorMessageUTF8(ErrorCode: Integer): String;
96+```
97+
98+### Puste nazwy plików i podwójne separatory ścieżki
99+
100+Istnieją pewne różnice w obsłudze nazw plików/katalogów w systemie Windows w porównaniu z systemami Linux, Unix i Unix.
101+
102+- Windows zezwala na puste nazwy plików. Dlatego FileExistsUTF8('..\\') sprawdza w systemie Windows w katalogu nadrzędnym, czy istnieje plik bez nazwy.
103+- 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ę.
104+
105+Podwójne separatory ścieżki w nazwach plików są również traktowane inaczej:
106+
107+- Windows: 'C:\\' to nie to samo co 'C:\\\\'
108+- Uniksy: ścieżka '/usr//' jest taka sama jak '/usr/'. Jeśli '/usr' jest katalogiem, to nawet wszystkie trzy zapisy są takie same.
109+
110+Jest to ważne przy łączeniu nazw plików. Na przykład:
111+
112+``` pascal
113+FullFilename:=FilePath+PathDelim+ShortFilename; // może skutkować dwoma znakami PathDelims, które dają różne wyniki pod Windows i Linux
114+FullFilename:=AppendPathDelim(FilePath) + ShortFilename; // tworzy tylko jeden znak PathDelim
115+FullFilename:=TrimFilename(FilePath+PathDelim+ShortFilename); // tworzy tylko jeden znak PathDelim i czyści ścieżkę
116+```
117+
118+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.
119+
120+Jeśli chcesz wiedzieć, czy katalog istnieje, użyj **DirectoryExistsUTF8**.
121+
122+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.
123+
124+- 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.
125+- W systemie Windows musisz użyć funkcji DirectoryExistsUTF8, ale wcześniej musisz usunąć separator ścieżki, na przykład za pomocą funkcji ChompPathDelim.
126+
127+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ę.
128+
129+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').
130+
131+### Kodowanie tekstu
132+
133+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:
134+
135+``` pascal
136+function GuessEncoding(const s: string): string;
137+function GetDefaultTextEncoding: string;
138+```
139+
140+oraz zawiera funkcje do konwersji z jednego kodowania na inne:
141+
142+``` pascal
143+function ConvertEncoding(const s, FromEncoding, ToEncoding: string): string;
144+
145+function UTF8BOMToUTF8(const s: string): string; // UTF8 z BOM
146+function ISO_8859_1ToUTF8(const s: string): string; // Europa Środkowa
147+function CP1250ToUTF8(const s: string): string; // Europa Środkowa
148+function CP1251ToUTF8(const s: string): string; // cyrylica
149+function CP1252ToUTF8(const s: string): string; // Latin-1 (Europa Zachodnia)
150+...
151+function UTF8ToUTF8BOM(const s: string): string; // UTF8 z BOM
152+function UTF8ToISO_8859_1(const s: string): string; // Europa Środkowa
153+function UTF8ToCP1250(const s: string): string; // Europa Środkowa
154+function UTF8ToCP1251(const s: string): string; // cyrylica
155+function UTF8ToCP1252(const s: string): string; // Latin-1 (Europa Zachodnia)
156+...
157+```
158+
159+Na przykład, aby załadować plik tekstowy i przekonwertować go na UTF-8, możesz użyć:
160+
161+``` pascal
162+var
163+ sl: TStringList;
164+ OriginalText: String;
165+ TextAsUTF8: String;
166+begin
167+ sl:=TStringList.Create;
168+ try
169+ sl.LoadFromFile('jakis_tekst.txt'); // uwaga: zmienia to zakończenia linii na systemowe zakończenia linii
170+ OriginalText:=sl.Text;
171+ TextAsUTF8:=ConvertEncoding(OriginalText,GuessEncoding(OriginalText),EncodingUTF8);
172+ ...
173+ finally
174+ sl.Free;
175+ end;
176+end;
177+```
178+
179+Aby zapisać plik tekstowy w kodowaniu systemowym, możesz użyć:
180+
181+``` pascal
182+sl.Text:=ConvertEncoding(TextAsUTF8,EncodingUTF8,GetDefaultTextEncoding);
183+sl.SaveToFile('jakis_tekst.txt');
184+```
185+
186+### Pliki konfiguracyjne
187+
188+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.
189+
190+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:
191+
192+``` pascal
193+ConfigFilePath := GetAppConfigFile(False);
194+```
195+
196+Poniżej znajdują się przykłady funkcji wypisujące domyślne ścieżki w różnych systemach:
197+
198+``` pascal
199+program project1;
200+
201+{$mode objfpc}{$H+}
202+
203+uses
204+ SysUtils;
205+
206+begin
207+ WriteLn(GetAppConfigDir(True));
208+ WriteLn(GetAppConfigDir(False));
209+ WriteLn(GetAppConfigFile(True));
210+ WriteLn(GetAppConfigFile(False));
211+end.
212+```
213+
214+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.
215+
216+> **Note:** Zwykli użytkownicy nie mogą pisać do katalogu /etc. Mogą to zrobić tylko użytkownicy z uprawnieniami administratora.
217+
218+Zauważ, że przed FPC 2.2.4 funkcja korzystała z katalogu, w którym aplikacja przechowywała globalne konfiguracje systemu Windows.
219+
220+Dane wyjściowe w systemie Windows 98 z FPC 2.2.0:
221+
222+ C:\Program Files\PROJECT1
223+ C:\Windows\Local Settings\Application Data\PROJECT1
224+ C:\Program Files\PROJECT1\PROJECT1.cfg
225+ C:\Windows\Local Settings\Application Data\PROJECT1\PROJECT1.cfg
226+
227+Dane wyjściowe w systemie Windows XP z FPC 3.0.4:
228+
229+ C:\Documents and Settings\All Users\Application Data\project1\
230+ C:\Documents and Settings\user\Local Settings\Application Data\project1\
231+ C:\Documents and Settings\All Users\Application Data\project1\project1.cfg
232+ C:\Documents and Settings\user\Local Settings\Application Data\project1\project1.cfg
233+
234+Dane wyjściowe w systemach Windows 7 i Windows 10 z FPC 3.0.4:
235+
236+ C:\ProgramData\project1\
237+ C:\Users\user\AppData\Local\project1\
238+ C:\ProgramData\project1\project1.cfg
239+ C:\Users\user\AppData\Local\project1\project1.cfg
240+
241+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):
242+
243+ /etc/project1/
244+ /Users/user/.config/project1/
245+ /etc/project1.cfg
246+ /Users/user/.config/project1.cfg
247+
248+Dane wyjściowe na FreeBSD 12.1 z FPC 3.0.4:
249+
250+ /etc/project1/
251+ /home/user/.config/project1/
252+ /etc/project1.cfg
253+ /home/user/.config/project1.cfg
254+
255+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 [[Boolean|logiczny]]: `WriteLn(GetAppConfigFile(True,True));`.
256+
257+> **Note:** Użycie UPX zakłóca korzystanie z funkcji GetAppConfigDir i GetAppConfigFile.
258+
259+#### macOS
260+
261+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.
262+
263+### Pliki danych i zasobów
264+
265+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.
266+
267+#### Windows
268+
269+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.
270+
271+W skrócie: użyj takiego folderu:
272+
273+``` pascal
274+ OpDirLocal:= GetEnvironmentVariableUTF8('appdata')+'\MyAppName';
275+```
276+
277+Zobacz: [[Windows Programming Tips|Wskazówki dotyczące programowania w systemie Windows — uzyskiwanie specjalnych folderów]]
278+
279+#### Unix/Linux
280+
281+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.
282+
283+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.
284+
285+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ą.
286+
287+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|plikami konfiguracyjnymi]].
288+
289+#### macOS
290+
291+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:
292+
293+- plik wykonywalny to "path/MojaAplikacja.app/Contents/MacOS/myapp"
294+- katalog zasobów to "path/MojaAplikacja.app/Contents/Resources"
295+
296+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]].
297+
298+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]].
299+
300+> **Warning:** **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 [[Locating the macOS application resources directory|tym artykule]].
301+
302+### 32/64 bit
303+
304+#### Wykrywanie wersji bitowej systemu w czasie wykonywania
305+
306+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: [[Detect Windows x32-x64 example|Wykryj Windows x32-x64]].
307+
308+#### Wykrywanie wersji bitowej zewnętrznej biblioteki przed jej załadowaniem
309+
310+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](http://forum.lazarus.freepascal.org/index.php/topic,36834.msg245859.html#msg245859)) (komentarze zostały przetłumaczone):
311+
312+``` pascal
313+
314+uses {..., } JwaWindows;
315+
316+function GetPEType(const APath: WideString): Byte;
317+const
318+ PE_UNKNOWN = 0; //jeśli plik nie jest poprawną biblioteką dll, zwracane jest 0
319+ // PE_16BIT = 1; // nieobsługiwane przez tę funkcję
320+ PE_32BIT = 2;
321+ PE_64BIT = 3;
322+var
323+ hFile, hFileMap: THandle;
324+ PMapView: Pointer;
325+ PIDH: PImageDosHeader;
326+ PINTH: PImageNtHeaders;
327+ Base: Pointer;
328+begin
329+ Result := PE_UNKNOWN;
330+
331+ hFile := CreateFileW(PWideChar(APath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
332+ if hFile = INVALID_HANDLE_VALUE then
333+ begin
334+ CloseHandle(hFile);
335+ Exit;
336+ end;
337+
338+ hFileMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
339+ if hFileMap = 0 then
340+ begin
341+ CloseHandle(hFile);
342+ CloseHandle(hFileMap);
343+ Exit;
344+ end;
345+
346+ PMapView := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
347+ if PMapView = nil then
348+ begin
349+ CloseHandle(hFile);
350+ CloseHandle(hFileMap);
351+ Exit;
352+ end;
353+
354+ PIDH := PImageDosHeader(PMapView);
355+ if PIDH^.e_magic <> IMAGE_DOS_SIGNATURE then
356+ begin
357+ CloseHandle(hFile);
358+ CloseHandle(hFileMap);
359+ UnmapViewOfFile(PMapView);
360+ Exit;
361+ end;
362+
363+ Base := PIDH;
364+ PINTH := PIMAGENTHEADERS(Base + LongWord(PIDH^.e_lfanew));
365+ if PINTH^.Signature = IMAGE_NT_SIGNATURE then
366+ begin
367+ case PINTH^.OptionalHeader.Magic of
368+ $10b: Result := PE_32BIT;
369+ $20b: Result := PE_64BIT
370+ end;
371+ end;
372+
373+ CloseHandle(hFile);
374+ CloseHandle(hFileMap);
375+ UnmapViewOfFile(PMapView);
376+end;
377+
378+//Teraz, jeśli skompilujesz swoją aplikację dla 32-bitowych i 64-bitowych wersji Windows,
379+//możesz sprawdzić, czy wersja bitowa dll jest taka sama jak w Twojej aplikacji:
380+function IsCorrectBitness(const APath: WideString): Boolean;
381+begin
382+ {$ifdef CPU32}
383+ Result := GetPEType(APath) = 2; //aplikacja jest kompilowana jako 32-bitowa, pytamy czy GetPeType zwraca 2
384+ {$endif}
385+ {$ifdef CPU64}
386+ Result := GetPEType(APath) = 3; //aplikacja jest kompilowana jako 64-bitowa, pytamy czy GetPeType zwraca 3
387+ {$endif}
388+end;
389+```
390+
391+#### Typy wskaźników / liczb całkowitych
392+
393+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.
394+
395+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.
396+
397+Użyj dla kodu, który powinien działać z Delphi i FPC:
398+
399+``` pascal
400+ {$IFNDEF FPC}
401+ type
402+ PtrInt = integer;
403+ PtrUInt = cardinal;
404+ {$ENDIF}
405+```
406+
407+Zamień wszystkie rzutowania wskaźnika **Integer(SomePointerOrObject)** na **PtrInt(SomePointerOrObject)**.
408+
409+### Kolejność bajtów
410+
411+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.
412+
413+Użyj dla kodu, który powinien działać na obu systemach:
414+
415+``` pascal
416+{$IFDEF ENDIAN_BIG}
417+...
418+{$ELSE}
419+...
420+{$ENDIF}
421+```
422+
423+Przeciwieństwo dla ENDIAN_BIG to ENDIAN_LITTLE.
424+
425+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*).
426+
427+#### Libc i inne jednostki specjalne
428+
429+Unikaj starszych modułów, takich jak „oldlinux” i „libc”, które nie są obsługiwane poza linux/i386.
430+
431+#### Asembler
432+
433+Unikaj używania [[Assembly language|asemblera]].
434+
435+#### Dyrektywy kompilatora
436+
437+``` pascal
438+{$ifdef CPU32}
439+...tutaj napisz kod dla procesorów 32-bitowych
440+{$ENDIF}
441+{$ifdef CPU64}
442+...tutaj napisz kod dla procesorów 64-bitowych
443+{$ENDIF}
444+```
445+
446+### Projekty, pakiety i ścieżki wyszukiwania
447+
448+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.
449+
450+Kilka rad, jak to osiągnąć.
451+
452+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.
453+
454+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|Tworzenie pakietu dla wspólnych modułów]].
455+
456+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.
457+
458+#### Moduły zależne od platformy
459+
460+Na przykład moduł wintricks.pas powinien być używany tylko w systemie Windows. W sekcji **uses** użyj:
461+
462+``` pascal
463+uses
464+ Classes, SysUtils
465+ {$IFDEF Windows}
466+ ,WinTricks
467+ {$ENDIF}
468+ ;
469+```
470+
471+Jeśli moduł jest częścią pakietu, należy również wybrać ten moduł w edytorze pakietów i odznaczyć pole wyboru *Use unit*.
472+
473+Zobacz także [[Lazarus Packages|Moduły zależne od platformy]]
474+
475+#### Ścieżki wyszukiwania specyficzne dla platformy
476+
477+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.
478+
479+Przykład jednego pliku include dla każdego zestawu widżetów LCL:
480+
481+Utwórz jeden plik dla każdego zestawu widżetów, który chcesz obsługiwać:
482+
483+`win32/example.inc`\
484+`gtk/example.inc`\
485+`gtk2/example.inc`\
486+`carbon/example.inc`
487+
488+Nie musisz dodawać plików do pakietu lub projektu. Dodaj ścieżkę wyszukiwania include *\$(LCLWidgetType)* do opcji kompilatora pakietu lub projektu.
489+
490+W swoim module użyj dyrektywy: {\$I example.inc}
491+
492+Oto kilka przydatnych makr i typowych wartości:
493+
494+- LCLWidgetType: win32, gtk, gtk2, qt, carbon, fpgui, nogui
495+- TargetOS: linux, win32, win64, wince, freebsd, netbsd, openbsd, darwin (many more)
496+- TargetCPU: i386, x86_64, arm, powerpc, sparc
497+- SrcOS: win, unix
498+
499+Do używania zmiennych środowiskowych można użyć makra \$Env().
500+
501+I oczywiście możesz używać ich kombinacji. Na przykład LCL wykorzystuje:
502+
503+`$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS);$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType)`
504+
505+Zobacz tutaj pełną listę makr: [[IDE Macros in paths and filenames|Makra IDE w ścieżkach i nazwach plików]].
506+
507+#### Ścieżki wyszukiwania specyficzne dla maszyny/użytkownika
508+
509+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.
510+
511+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.
512+
513+### Różnice regionalne
514+
515+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.
516+
517+Następne sekcje wyjaśniają, jak to zrobić.
518+
519+#### macOS
520+
521+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.
522+
523+#### StrToFloat
524+
525+Nowy zestaw ustawień formatu, który ustawia stały separator dziesiętny, można utworzyć za pomocą następującego kodu:
526+
527+``` pascal
528+// w pliku projektu .lpr
529+uses
530+...
531+{$IFDEF UNIX}
532+clocale
533+{ wymagane w systemie Linux/Unix do obsługi ustawień formatów. Powinien być jednym z pierwszych (prawdopodobnie po cthreads?}
534+{$ENDIF}
535+```
536+
537+and:
538+
539+``` pascal
540+// w twoim kodzie:
541+var
542+ FPointSeparator, FCommaSeparator: TFormatSettings;
543+begin
544+ // Format settings to convert a string to a float
545+ // Ustawienia formatu, aby przekonwertować ciąg string na liczbę zmiennoprzecinkowąq
546+ FPointSeparator := DefaultFormatSettings;
547+ FPointSeparator.DecimalSeparator := '.';
548+ FPointSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
549+ FCommaSeparator := DefaultFormatSettings;
550+ FCommaSeparator.DecimalSeparator := ',';
551+ FCommaSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
552+```
553+
554+Później możesz użyć tych ustawień formatu podczas wywoływania StrToFloat, na przykład:
555+
556+``` pascal
557+// Ta funkcja działa jak StrToFloat, ale po prostu próbuje dwóch możliwych separatorów dziesiętnych
558+// Pozwoli to uniknąć wyjątku, gdy format ciągu string nie pasuje do ustawień regionalnych
559+function AnSemantico.StringToFloat(AStr: string): Double;
560+begin
561+ if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator)
562+ else Result := StrToFloat(AStr, FCommaSeparator);
563+end;
564+```
565+
566+### Gtk2 i maskowanie wyjątków FPU
567+
568+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.
569+
570+Po [tym zgłoszeniu na forum](http://www.lazarus.freepascal.org/index.php/topic,13460.0.html) i odpowiedziach na [ten raport o błędzie](http://bugs.freepascal.org/view.php?id=19674) stało się jasne, że nic nie można z tym zrobić, więc musimy wiedzieć, czym właściwie są te różnice.
571+
572+Dlatego zróbmy test:
573+
574+``` pascal
575+uses
576+ ..., math,...
577+
578+{...}
579+
580+var
581+ FPUException: TFPUException;
582+ FPUExceptionMask: TFPUExceptionMask;
583+begin
584+ FPUExceptionMask := GetExceptionMask;
585+ for FPUException := Low(TFPUException) to High(TFPUException) do begin
586+ write(FPUException, ' - ');
587+ if not (FPUException in FPUExceptionMask) then
588+ write('not ');
589+
590+ writeln('masked!');
591+ end;
592+ readln;
593+end.
594+```
595+
596+Nasz prosty program otrzyma domyślne wartości FPC:
597+
598+ exInvalidOp - not masked!
599+ exDenormalized - masked!
600+ exZeroDivide - not masked!
601+ exOverflow - not masked!
602+ exUnderflow - masked!
603+ exPrecision - masked!
604+
605+Jednak w przypadku Gtk2 tylko exOverflow nie jest maskowany.
606+
607+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:
608+
609+``` pascal
610+var
611+ X, A, B: Double;
612+// ...
613+
614+try
615+ X := A / B;
616+ // blok kodu 1
617+except
618+ // blok kodu 2
619+end;
620+// ...
621+```
622+
623+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](http://www.freepascal.org/docs-html/rtl/math/infinity.html), [NegInfinity](http://www.freepascal.org/docs-html/rtl/math/neginfinity.html) lub [NaN](http://www.freepascal.org/docs-html/rtl/math/nan.html) i „blok kodu 1” zostanie wykonany.
624+
625+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:
626+
627+``` pascal
628+uses
629+ ..., math,...
630+
631+//...
632+var
633+ X, A, B: Double;
634+ Ind: Boolean;
635+// ...
636+try
637+ X := A / B;
638+ Ind := IsInfinite(X) or IsNan(X); // z gtk2 wpadamy tutaj
639+except
640+ Ind := True; // w Windows wpadamy tutaj, gdy B równa się zero
641+end;
642+if Ind then begin
643+ // blok kodu 2
644+end else begin
645+ // blok kodu 1
646+end;
647+// ...
648+```
649+
650+Lub:
651+
652+``` pascal
653+uses
654+ ..., math,...
655+
656+//...
657+var
658+ X, A, B: Double;
659+ FPUExceptionMask: TFPUExceptionMask;
660+// ...
661+
662+try
663+ FPUExceptionMask := GetExceptionMask;
664+ SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]); // niemaskowane
665+ try
666+ X := A / B;
667+ finally
668+ SetExceptionMask(FPUExceptionMask); // natychmiast zwróć poprzednie maskowanie, nie możemy pozwolić, aby wewnętrzne elementy Gtk2 były wywoływane bez maski
669+ end;
670+ // blok kodu 1
671+except
672+ // blok kodu 2
673+end;
674+// ...
675+```
676+
677+Bądź ostrożny, nie rób czegoś takiego (wywołanie LCL z wciąż zdjętą maską):
678+
679+``` pascal
680+try
681+ FPUExceptionMask := GetExceptionMask;
682+ SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
683+ try
684+ 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!
685+ finally
686+ SetExceptionMask(FPUExceptionMask);
687+ end;
688+ // blok kodu 1
689+except
690+ // blok kodu 2
691+end;
692+// ...
693+```
694+
695+Ale użyj zmiennej pomocniczej:
696+
697+``` pascal
698+try
699+ FPUExceptionMask := GetExceptionMask;
700+ SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
701+ try
702+ X := A / B; // Najpierw ustawiamy zmienną pomocniczą X
703+ finally
704+ SetExceptionMask(FPUExceptionMask);
705+ end;
706+ Edit1.Text := FloatToStr(X); // Teraz możemy ustawić tekst w Edit.
707+ // blok kodu 1
708+except
709+ // blok kodu 2
710+end;
711+// ...
712+```
713+
714+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.
715+
716+## Problemy przy przejściu z systemu Windows do *nix itp.
717+
718+W tym miejscu opisano problemy specyficzne dla systemów Linux, macOS, Android i innych Uniksów. Nie wszystkie tematy mogą dotyczyć wszystkich platform.
719+
720+### W Uniksie nie ma „katalogu aplikacji”
721+
722+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.).
723+
724+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).
725+
726+Aby tego uniknąć, przeczytaj sekcje dotyczące [[Multiplatform Programming Guide/pl|plików konfiguracyjnych]] i [[Multiplatform Programming Guide/pl|plików danych]].
727+
728+### Obycie się bez Windows COM Automation
729+
730+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](http://wiki.lazarus.freepascal.org/Office_Automation#Using_COM_Automation_to_interact_with_OpenOffice_and_Microsoft_Office).
731+
732+#### alternatywa dla macOS
733+
734+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.
735+
736+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):
737+
738+```applescript
739+ tell application "NeoOffice"
740+ launch
741+ end tell
742+```
743+
744+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:
745+
746+``` pascal
747+ fpsystem('myscript.applescript');
748+```
749+
750+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:
751+
752+``` pascal
753+ fpsystem('osascript -e '#39'tell application "NeoOffice"'#39 +
754+ ' -e '#39'launch'#39' -e '#39'end tell'#39);
755+ {Zwróć uwagę na użycie #39 jako pojedynczego cudzysłowu do parametrów}
756+```
757+
758+Jednak te przykłady są tylko odpowiednikiem następującego polecenia Open (otwórz):
759+
760+``` pascal
761+ fpsystem('open -a NeoOffice');
762+```
763+
764+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ą:
765+
766+``` pascal
767+ fpsystem('open -a safari "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');
768+```
769+
770+i
771+
772+``` pascal
773+ fpsystem('open -a mail "mailto:ss4200@invalid.org"');
774+```
775+
776+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:
777+
778+``` pascal
779+ fpsystem('open "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');
780+```
781+
782+i
783+
784+``` pascal
785+ fpsystem('open "mailto:ss4200@invalid.org"');
786+```
787+
788+Nie zapomnij dołączyć modułu Unix do klauzuli uses, jeśli używasz `fpsystem` lub `shell` (wymiennie).
789+
790+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.
791+
792+#### Alternatywy dla Linuksa
793+
794+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).
795+
796+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.
797+
798+### Alternatywy dla funkcji Windows API
799+
800+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} ).
801+
802+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.
803+
804+### Kody klawiszy
805+
806+Na szczęście wykrywanie kodów klawiszy (np. w zdarzeniach KeyUp) jest przenośne: patrz [[LCL Key Handling|Obsługa klawiszy LCL]].
807+
808+### Instalowanie swojej aplikacji
809+
810+Zobacz [[Deploying Your Application|Wdrażanie swojej aplikacji]].
811+
812+## Zobacz także
813+
814+- [[Writing portable code regarding the processor architecture|Pisanie przenośnego kodu dotyczącego architektury procesora]]
815+- [[Introduction to platform-sensitive development|Wprowadzenie do rozwoju zależnego od platformy]]
816+- [[Apple-specific UI elements|Elementy interfejsu użytkownika specyficzne dla Apple]]
817+
818+## Linki zewnętrzne
819+
820+- <http://www.midnightbeach.com/KylixForDelphiProgrammers.html> Przewodnik dla programistów Windows zaczynających pracę z Kylix. Wiele pojęć / fragmentów kodu dotyczy Lazarusa.
821+
822+- <http://www.stack.nl/~marcov/porting.pdf> Przewodnik po pisaniu przenośnego kodu źródłowego, głównie pomiędzy różnymi kompilatorami.
823+
824+---
825+*From the Free Pascal wiki, page "Multiplatform Programming Guide/pl", as it stood on 2021-11-01 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history