Sign in Join
Wiki copytemporary

Multiplatform Programming Guide/pl: what changed

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

OldNewLine
1-<div style="font-size:1.88em;margin:0.75em 0;">
2-
31Przewodnik programowania wieloplatformowego
4-
5-</div>
62
73To 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]].
84
95Wię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”]].
106
117## Wprowadzenie do programowania wieloplatformowego (międzyplatformowego)
128
139### Ile platform potrzebujesz?
1410
1511Aby 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ę.
1612
1713Jeś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.
1814
1915Popularność 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.
2016
2117W 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.
2218
2319Jeś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.
2420
2521Po 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:
2622
2723- [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).
2824- [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).
2925- [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).
3026- [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).
3127- [VirtualBox](https://www.virtualbox.org/) - Na systemie hosta może działać Intel macOS, Windows, Linux lub Solaris (Open Source).
3228
3329Niektóre z nich, np. Parallels na Macu, sprawiają, że instalacja stacjonarnego systemu operacyjnego Linux za pomocą jednego kliknięcia jest banalna.
3430
3531**Zobacz także:** [[Small Virtual Machines|Małe maszyny wirtualne]] i [[Qemu and other emulators|Qemu i inne emulatory]].
3632
3733## Programowanie międzyplatformowe
3834
3935### Praca z plikami i folderami
4036
4137Podczas 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.
4238
4339- **PathSep**, **PathSeparator**: separator ścieżek używany podczas dodawania wielu ścieżek razem (';', ...)
4440- **PathDelim**, **DirectorySeparator**: separator katalogów dla każdej platformy ('/', '\\', ...)
4541- **LineEnding**: poprawna sekwencja znaków końca wiersza (#13#10 - CRLF, \#10 - [[Line feed|LF]], ...)
4642
4743Inną 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.
4844
4945Szczegó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.
5046
5147macOS 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.
5248
5349Funkcje 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.
5450
5551``` pascal
5652// Funkcje AnsiToUTF8 i UTF8ToAnsi wymagają menedżera widestring pod Linuksem, BSD, macOS,
5753// ale zwykle te systemy operacyjne używają UTF-8 jako kodowania systemowego, więc widestringmanager
5854// nie jest potrzebny.
5955function NeedRTLAnsi: boolean;// true if system encoding is not UTF-8
6056procedure SetNeedRTLAnsi(NewValue: boolean);
6157function UTF8ToSys(const s: string): string; // podobna do UTF8ToAnsi, ale nie jest już zależna od widestringmanager
6258function SysToUTF8(const s: string): string; // podobna do AnsiToUTF8, ale nie jest już zależna od widestringmanager
6359function UTF8ToConsole(const s: string): string; // konwertuje ciąg znaków UTF8 na kodowanie konsoli (używane przez Write, WriteLn)
6460
6561// operacje na plikach
6662function FileExistsUTF8(const Filename: string): boolean;
6763function FileAgeUTF8(const FileName: string): Longint;
6864function DirectoryExistsUTF8(const Directory: string): Boolean;
6965function ExpandFileNameUTF8(const FileName: string): string;
7066function ExpandUNCFileNameUTF8(const FileName: string): string;
7167function ExtractShortPathNameUTF8(Const FileName : String) : String;
7268function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint;
7369function FindNextUTF8(var Rslt: TSearchRec): Longint;
7470procedure FindCloseUTF8(var F: TSearchrec);
7571function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;
7672function FileGetAttrUTF8(const FileName: String): Longint;
7773function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;
7874function DeleteFileUTF8(const FileName: String): Boolean;
7975function RenameFileUTF8(const OldName, NewName: String): Boolean;
8076function FileSearchUTF8(const Name, DirList : String): String;
8177function FileIsReadOnlyUTF8(const FileName: String): Boolean;
8278function GetCurrentDirUTF8: String;
8379function SetCurrentDirUTF8(const NewDir: String): Boolean;
8480function CreateDirUTF8(const NewDir: String): Boolean;
8581function RemoveDirUTF8(const Dir: String): Boolean;
8682function ForceDirectoriesUTF8(const Dir: string): Boolean;
8783
8884// środowisko
8985function ParamStrUTF8(Param: Integer): string;
9086function GetEnvironmentStringUTF8(Index: Integer): string;
9187function GetEnvironmentVariableUTF8(const EnvVar: string): String;
9288function GetAppConfigDirUTF8(Global: Boolean): string;
9389
9490// inne
9591function SysErrorMessageUTF8(ErrorCode: Integer): String;
9692```
9793
9894### Puste nazwy plików i podwójne separatory ścieżki
9995
10096Istnieją pewne różnice w obsłudze nazw plików/katalogów w systemie Windows w porównaniu z systemami Linux, Unix i Unix.
10197
10298- Windows zezwala na puste nazwy plików. Dlatego FileExistsUTF8('..\\') sprawdza w systemie Windows w katalogu nadrzędnym, czy istnieje plik bez nazwy.
10399- 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ę.
104100
105101Podwójne separatory ścieżki w nazwach plików są również traktowane inaczej:
106102
107103- Windows: 'C:\\' to nie to samo co 'C:\\\\'
108104- Uniksy: ścieżka '/usr//' jest taka sama jak '/usr/'. Jeśli '/usr' jest katalogiem, to nawet wszystkie trzy zapisy są takie same.
109105
110106Jest to ważne przy łączeniu nazw plików. Na przykład:
111107
112108``` pascal
113109FullFilename:=FilePath+PathDelim+ShortFilename; // może skutkować dwoma znakami PathDelims, które dają różne wyniki pod Windows i Linux
114110FullFilename:=AppendPathDelim(FilePath) + ShortFilename; // tworzy tylko jeden znak PathDelim
115111FullFilename:=TrimFilename(FilePath+PathDelim+ShortFilename); // tworzy tylko jeden znak PathDelim i czyści ścieżkę
116112```
117113
118114Funkcja 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.
119115
120116Jeśli chcesz wiedzieć, czy katalog istnieje, użyj **DirectoryExistsUTF8**.
121117
122118Innym 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.
123119
124120- 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.
125121- W systemie Windows musisz użyć funkcji DirectoryExistsUTF8, ale wcześniej musisz usunąć separator ścieżki, na przykład za pomocą funkcji ChompPathDelim.
126122
127123W 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ę.
128124
129125Zauważ, ż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').
130126
131127### Kodowanie tekstu
132128
133129Pliki 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:
134130
135131``` pascal
136132function GuessEncoding(const s: string): string;
137133function GetDefaultTextEncoding: string;
138134```
139135
140136oraz zawiera funkcje do konwersji z jednego kodowania na inne:
141137
142138``` pascal
143139function ConvertEncoding(const s, FromEncoding, ToEncoding: string): string;
144140
145141function UTF8BOMToUTF8(const s: string): string; // UTF8 z BOM
146142function ISO_8859_1ToUTF8(const s: string): string; // Europa Środkowa
147143function CP1250ToUTF8(const s: string): string; // Europa Środkowa
148144function CP1251ToUTF8(const s: string): string; // cyrylica
149145function CP1252ToUTF8(const s: string): string; // Latin-1 (Europa Zachodnia)
150146...
151147function UTF8ToUTF8BOM(const s: string): string; // UTF8 z BOM
152148function UTF8ToISO_8859_1(const s: string): string; // Europa Środkowa
153149function UTF8ToCP1250(const s: string): string; // Europa Środkowa
154150function UTF8ToCP1251(const s: string): string; // cyrylica
155151function UTF8ToCP1252(const s: string): string; // Latin-1 (Europa Zachodnia)
156152...
157153```
158154
159155Na przykład, aby załadować plik tekstowy i przekonwertować go na UTF-8, możesz użyć:
160156
161157``` pascal
162158var
163159 sl: TStringList;
164160 OriginalText: String;
165161 TextAsUTF8: String;
166162begin
167163 sl:=TStringList.Create;
168164 try
169165 sl.LoadFromFile('jakis_tekst.txt'); // uwaga: zmienia to zakończenia linii na systemowe zakończenia linii
170166 OriginalText:=sl.Text;
171167 TextAsUTF8:=ConvertEncoding(OriginalText,GuessEncoding(OriginalText),EncodingUTF8);
172168 ...
173169 finally
174170 sl.Free;
175171 end;
176172end;
177173```
178174
179175Aby zapisać plik tekstowy w kodowaniu systemowym, możesz użyć:
180176
181177``` pascal
182178sl.Text:=ConvertEncoding(TextAsUTF8,EncodingUTF8,GetDefaultTextEncoding);
183179sl.SaveToFile('jakis_tekst.txt');
184180```
185181
186182### Pliki konfiguracyjne
187183
188184Moż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.
189185
190186Istnieje 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:
191187
192188``` pascal
193189ConfigFilePath := GetAppConfigFile(False);
194190```
195191
196192Poniżej znajdują się przykłady funkcji wypisujące domyślne ścieżki w różnych systemach:
197193
198194``` pascal
199195program project1;
200196
201197{$mode objfpc}{$H+}
202198
203199uses
204200 SysUtils;
205201
206202begin
207203 WriteLn(GetAppConfigDir(True));
208204 WriteLn(GetAppConfigDir(False));
209205 WriteLn(GetAppConfigFile(True));
210206 WriteLn(GetAppConfigFile(False));
211207end.
212208```
213209
214210Moż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.
215211
216212> **Note:** Zwykli użytkownicy nie mogą pisać do katalogu /etc. Mogą to zrobić tylko użytkownicy z uprawnieniami administratora.
217213
218214Zauważ, że przed FPC 2.2.4 funkcja korzystała z katalogu, w którym aplikacja przechowywała globalne konfiguracje systemu Windows.
219215
220216Dane wyjściowe w systemie Windows 98 z FPC 2.2.0:
221217
222218 C:\Program Files\PROJECT1
223219 C:\Windows\Local Settings\Application Data\PROJECT1
224220 C:\Program Files\PROJECT1\PROJECT1.cfg
225221 C:\Windows\Local Settings\Application Data\PROJECT1\PROJECT1.cfg
226222
227223Dane wyjściowe w systemie Windows XP z FPC 3.0.4:
228224
229225 C:\Documents and Settings\All Users\Application Data\project1\
230226 C:\Documents and Settings\user\Local Settings\Application Data\project1\
231227 C:\Documents and Settings\All Users\Application Data\project1\project1.cfg
232228 C:\Documents and Settings\user\Local Settings\Application Data\project1\project1.cfg
233229
234230Dane wyjściowe w systemach Windows 7 i Windows 10 z FPC 3.0.4:
235231
236232 C:\ProgramData\project1\
237233 C:\Users\user\AppData\Local\project1\
238234 C:\ProgramData\project1\project1.cfg
239235 C:\Users\user\AppData\Local\project1\project1.cfg
240236
241237Dane 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):
242238
243239 /etc/project1/
244240 /Users/user/.config/project1/
245241 /etc/project1.cfg
246242 /Users/user/.config/project1.cfg
247243
248244Dane wyjściowe na FreeBSD 12.1 z FPC 3.0.4:
249245
250246 /etc/project1/
251247 /home/user/.config/project1/
252248 /etc/project1.cfg
253249 /home/user/.config/project1.cfg
254250
255251Obserwator 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));`.
256252
257253> **Note:** Użycie UPX zakłóca korzystanie z funkcji GetAppConfigDir i GetAppConfigFile.
258254
259255#### macOS
260256
261257W 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.
262258
263259### Pliki danych i zasobów
264260
265261Bardzo 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.
266262
267263#### Windows
268264
269265W 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.
270266
271267W skrócie: użyj takiego folderu:
272268
273269``` pascal
274270 OpDirLocal:= GetEnvironmentVariableUTF8('appdata')+'\MyAppName';
275271```
276272
277273Zobacz: [[Windows Programming Tips|Wskazówki dotyczące programowania w systemie Windows — uzyskiwanie specjalnych folderów]]
278274
279275#### Unix/Linux
280276
281277W 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.
282278
283279Dane 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.
284280
285281Pliki 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ą.
286282
287283Pliki 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]].
288284
289285#### macOS
290286
291287macOS 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:
292288
293289- plik wykonywalny to "path/MojaAplikacja.app/Contents/MacOS/myapp"
294290- katalog zasobów to "path/MojaAplikacja.app/Contents/Resources"
295291
296292Dane 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]].
297293
298294Pliki 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]].
299295
300296> **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]].
301297
302298### 32/64 bit
303299
304300#### Wykrywanie wersji bitowej systemu w czasie wykonywania
305301
306302Chociaż 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]].
307303
308304#### Wykrywanie wersji bitowej zewnętrznej biblioteki przed jej załadowaniem
309305
310306Kiedy 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):
311307
312308``` pascal
313309
314310uses {..., } JwaWindows;
315311
316312function GetPEType(const APath: WideString): Byte;
317313const
318314 PE_UNKNOWN = 0; //jeśli plik nie jest poprawną biblioteką dll, zwracane jest 0
319315 // PE_16BIT = 1; // nieobsługiwane przez tę funkcję
320316 PE_32BIT = 2;
321317 PE_64BIT = 3;
322318var
323319 hFile, hFileMap: THandle;
324320 PMapView: Pointer;
325321 PIDH: PImageDosHeader;
326322 PINTH: PImageNtHeaders;
327323 Base: Pointer;
328324begin
329325 Result := PE_UNKNOWN;
330326
331327 hFile := CreateFileW(PWideChar(APath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
332328 if hFile = INVALID_HANDLE_VALUE then
333329 begin
334330 CloseHandle(hFile);
335331 Exit;
336332 end;
337333
338334 hFileMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
339335 if hFileMap = 0 then
340336 begin
341337 CloseHandle(hFile);
342338 CloseHandle(hFileMap);
343339 Exit;
344340 end;
345341
346342 PMapView := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
347343 if PMapView = nil then
348344 begin
349345 CloseHandle(hFile);
350346 CloseHandle(hFileMap);
351347 Exit;
352348 end;
353349
354350 PIDH := PImageDosHeader(PMapView);
355351 if PIDH^.e_magic <> IMAGE_DOS_SIGNATURE then
356352 begin
357353 CloseHandle(hFile);
358354 CloseHandle(hFileMap);
359355 UnmapViewOfFile(PMapView);
360356 Exit;
361357 end;
362358
363359 Base := PIDH;
364360 PINTH := PIMAGENTHEADERS(Base + LongWord(PIDH^.e_lfanew));
365361 if PINTH^.Signature = IMAGE_NT_SIGNATURE then
366362 begin
367363 case PINTH^.OptionalHeader.Magic of
368364 $10b: Result := PE_32BIT;
369365 $20b: Result := PE_64BIT
370366 end;
371367 end;
372368
373369 CloseHandle(hFile);
374370 CloseHandle(hFileMap);
375371 UnmapViewOfFile(PMapView);
376372end;
377373
378374//Teraz, jeśli skompilujesz swoją aplikację dla 32-bitowych i 64-bitowych wersji Windows,
379375//możesz sprawdzić, czy wersja bitowa dll jest taka sama jak w Twojej aplikacji:
380376function IsCorrectBitness(const APath: WideString): Boolean;
381377begin
382378 {$ifdef CPU32}
383379 Result := GetPEType(APath) = 2; //aplikacja jest kompilowana jako 32-bitowa, pytamy czy GetPeType zwraca 2
384380 {$endif}
385381 {$ifdef CPU64}
386382 Result := GetPEType(APath) = 3; //aplikacja jest kompilowana jako 64-bitowa, pytamy czy GetPeType zwraca 3
387383 {$endif}
388384end;
389385```
390386
391387#### Typy wskaźników / liczb całkowitych
392388
393389Wskaź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.
394390
395391FPC 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.
396392
397393Użyj dla kodu, który powinien działać z Delphi i FPC:
398394
399395``` pascal
400396 {$IFNDEF FPC}
401397 type
402398 PtrInt = integer;
403399 PtrUInt = cardinal;
404400 {$ENDIF}
405401```
406402
407403Zamień wszystkie rzutowania wskaźnika **Integer(SomePointerOrObject)** na **PtrInt(SomePointerOrObject)**.
408404
409405### Kolejność bajtów
410406
411407Platformy 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.
412408
413409Użyj dla kodu, który powinien działać na obu systemach:
414410
415411``` pascal
416412{$IFDEF ENDIAN_BIG}
417413...
418414{$ELSE}
419415...
420416{$ENDIF}
421417```
422418
423419Przeciwieństwo dla ENDIAN_BIG to ENDIAN_LITTLE.
424420
425421Moduł **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*).
426422
427423#### Libc i inne jednostki specjalne
428424
429425Unikaj starszych modułów, takich jak „oldlinux” i „libc”, które nie są obsługiwane poza linux/i386.
430426
431427#### Asembler
432428
433429Unikaj używania [[Assembly language|asemblera]].
434430
435431#### Dyrektywy kompilatora
436432
437433``` pascal
438434{$ifdef CPU32}
439435...tutaj napisz kod dla procesorów 32-bitowych
440436{$ENDIF}
441437{$ifdef CPU64}
442438...tutaj napisz kod dla procesorów 64-bitowych
443439{$ENDIF}
444440```
445441
446442### Projekty, pakiety i ścieżki wyszukiwania
447443
448444Lazarus 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.
449445
450446Kilka rad, jak to osiągnąć.
451447
452448Kompilator 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.
453449
454450Każ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]].
455451
456452Każ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.
457453
458454#### Moduły zależne od platformy
459455
460456Na przykład moduł wintricks.pas powinien być używany tylko w systemie Windows. W sekcji **uses** użyj:
461457
462458``` pascal
463459uses
464460 Classes, SysUtils
465461 {$IFDEF Windows}
466462 ,WinTricks
467463 {$ENDIF}
468464 ;
469465```
470466
471467Jeśli moduł jest częścią pakietu, należy również wybrać ten moduł w edytorze pakietów i odznaczyć pole wyboru *Use unit*.
472468
473469Zobacz także [[Lazarus Packages|Moduły zależne od platformy]]
474470
475471#### Ścieżki wyszukiwania specyficzne dla platformy
476472
477473Kiedy 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.
478474
479475Przykład jednego pliku include dla każdego zestawu widżetów LCL:
480476
481477Utwórz jeden plik dla każdego zestawu widżetów, który chcesz obsługiwać:
482478
483479`win32/example.inc`\
484480`gtk/example.inc`\
485481`gtk2/example.inc`\
486482`carbon/example.inc`
487483
488484Nie musisz dodawać plików do pakietu lub projektu. Dodaj ścieżkę wyszukiwania include *\$(LCLWidgetType)* do opcji kompilatora pakietu lub projektu.
489485
490486W swoim module użyj dyrektywy: {\$I example.inc}
491487
492488Oto kilka przydatnych makr i typowych wartości:
493489
494490- LCLWidgetType: win32, gtk, gtk2, qt, carbon, fpgui, nogui
495491- TargetOS: linux, win32, win64, wince, freebsd, netbsd, openbsd, darwin (many more)
496492- TargetCPU: i386, x86_64, arm, powerpc, sparc
497493- SrcOS: win, unix
498494
499495Do używania zmiennych środowiskowych można użyć makra \$Env().
500496
501497I oczywiście możesz używać ich kombinacji. Na przykład LCL wykorzystuje:
502498
503499`$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS);$(LazarusDir)/lcl/units/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType)`
504500
505501Zobacz tutaj pełną listę makr: [[IDE Macros in paths and filenames|Makra IDE w ścieżkach i nazwach plików]].
506502
507503#### Ścieżki wyszukiwania specyficzne dla maszyny/użytkownika
508504
509505Na 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.
510506
511507Jeś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.
512508
513509### Różnice regionalne
514510
515511Niektó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.
516512
517513Następne sekcje wyjaśniają, jak to zrobić.
518514
519515#### macOS
520516
521517Zapoznaj 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.
522518
523519#### StrToFloat
524520
525521Nowy zestaw ustawień formatu, który ustawia stały separator dziesiętny, można utworzyć za pomocą następującego kodu:
526522
527523``` pascal
528524// w pliku projektu .lpr
529525uses
530526...
531527{$IFDEF UNIX}
532528clocale
533529{ wymagane w systemie Linux/Unix do obsługi ustawień formatów. Powinien być jednym z pierwszych (prawdopodobnie po cthreads?}
534530{$ENDIF}
535531```
536532
537533and:
538534
539535``` pascal
540536// w twoim kodzie:
541537var
542538 FPointSeparator, FCommaSeparator: TFormatSettings;
543539begin
544540 // Format settings to convert a string to a float
545541 // Ustawienia formatu, aby przekonwertować ciąg string na liczbę zmiennoprzecinkowąq
546542 FPointSeparator := DefaultFormatSettings;
547543 FPointSeparator.DecimalSeparator := '.';
548544 FPointSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
549545 FCommaSeparator := DefaultFormatSettings;
550546 FCommaSeparator.DecimalSeparator := ',';
551547 FCommaSeparator.ThousandSeparator := '#';// wyłącz separator tysięcy
552548```
553549
554550Później możesz użyć tych ustawień formatu podczas wywoływania StrToFloat, na przykład:
555551
556552``` pascal
557553// Ta funkcja działa jak StrToFloat, ale po prostu próbuje dwóch możliwych separatorów dziesiętnych
558554// Pozwoli to uniknąć wyjątku, gdy format ciągu string nie pasuje do ustawień regionalnych
559555function AnSemantico.StringToFloat(AStr: string): Double;
560556begin
561557 if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator)
562558 else Result := StrToFloat(AStr, FCommaSeparator);
563559end;
564560```
565561
566562### Gtk2 i maskowanie wyjątków FPU
567563
568564Biblioteka 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.
569565
570566Po [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.
571567
572568Dlatego zróbmy test:
573569
574570``` pascal
575571uses
576572 ..., math,...
577573
578574{...}
579575
580576var
581577 FPUException: TFPUException;
582578 FPUExceptionMask: TFPUExceptionMask;
583579begin
584580 FPUExceptionMask := GetExceptionMask;
585581 for FPUException := Low(TFPUException) to High(TFPUException) do begin
586582 write(FPUException, ' - ');
587583 if not (FPUException in FPUExceptionMask) then
588584 write('not ');
589585
590586 writeln('masked!');
591587 end;
592588 readln;
593589end.
594590```
595591
596592Nasz prosty program otrzyma domyślne wartości FPC:
597593
598594 exInvalidOp - not masked!
599595 exDenormalized - masked!
600596 exZeroDivide - not masked!
601597 exOverflow - not masked!
602598 exUnderflow - masked!
603599 exPrecision - masked!
604600
605601Jednak w przypadku Gtk2 tylko exOverflow nie jest maskowany.
606602
607603Konsekwencją 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:
608604
609605``` pascal
610606var
611607 X, A, B: Double;
612608// ...
613609
614610try
615611 X := A / B;
616612 // blok kodu 1
617613except
618614 // blok kodu 2
619615end;
620616// ...
621617```
622618
623619przyjmie 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.
624620
625621Moż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:
626622
627623``` pascal
628624uses
629625 ..., math,...
630626
631627//...
632628var
633629 X, A, B: Double;
634630 Ind: Boolean;
635631// ...
636632try
637633 X := A / B;
638634 Ind := IsInfinite(X) or IsNan(X); // z gtk2 wpadamy tutaj
639635except
640636 Ind := True; // w Windows wpadamy tutaj, gdy B równa się zero
641637end;
642638if Ind then begin
643639 // blok kodu 2
644640end else begin
645641 // blok kodu 1
646642end;
647643// ...
648644```
649645
650646Lub:
651647
652648``` pascal
653649uses
654650 ..., math,...
655651
656652//...
657653var
658654 X, A, B: Double;
659655 FPUExceptionMask: TFPUExceptionMask;
660656// ...
661657
662658try
663659 FPUExceptionMask := GetExceptionMask;
664660 SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]); // niemaskowane
665661 try
666662 X := A / B;
667663 finally
668664 SetExceptionMask(FPUExceptionMask); // natychmiast zwróć poprzednie maskowanie, nie możemy pozwolić, aby wewnętrzne elementy Gtk2 były wywoływane bez maski
669665 end;
670666 // blok kodu 1
671667except
672668 // blok kodu 2
673669end;
674670// ...
675671```
676672
677673Bądź ostrożny, nie rób czegoś takiego (wywołanie LCL z wciąż zdjętą maską):
678674
679675``` pascal
680676try
681677 FPUExceptionMask := GetExceptionMask;
682678 SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
683679 try
684680 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!
685681 finally
686682 SetExceptionMask(FPUExceptionMask);
687683 end;
688684 // blok kodu 1
689685except
690686 // blok kodu 2
691687end;
692688// ...
693689```
694690
695691Ale użyj zmiennej pomocniczej:
696692
697693``` pascal
698694try
699695 FPUExceptionMask := GetExceptionMask;
700696 SetExceptionMask(FPUExceptionMask - [exInvalidOp, exZeroDivide]);
701697 try
702698 X := A / B; // Najpierw ustawiamy zmienną pomocniczą X
703699 finally
704700 SetExceptionMask(FPUExceptionMask);
705701 end;
706702 Edit1.Text := FloatToStr(X); // Teraz możemy ustawić tekst w Edit.
707703 // blok kodu 1
708704except
709705 // blok kodu 2
710706end;
711707// ...
712708```
713709
714710We 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.
715711
716712## Problemy przy przejściu z systemu Windows do *nix itp.
717713
718714W tym miejscu opisano problemy specyficzne dla systemów Linux, macOS, Android i innych Uniksów. Nie wszystkie tematy mogą dotyczyć wszystkich platform.
719715
720716### W Uniksie nie ma „katalogu aplikacji”
721717
722718Wielu 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.).
723719
724720Nawet 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).
725721
726722Aby tego uniknąć, przeczytaj sekcje dotyczące [[Multiplatform Programming Guide/pl|plików konfiguracyjnych]] i [[Multiplatform Programming Guide/pl|plików danych]].
727723
728724### Obycie się bez Windows COM Automation
729725
730726W 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).
731727
732728#### alternatywa dla macOS
733729
734730Niestety, 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.
735731
736732AppleScript 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):
737733
738734```applescript
739735 tell application "NeoOffice"
740736 launch
741737 end tell
742738```
743739
744740Aplikacja 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:
745741
746742``` pascal
747743 fpsystem('myscript.applescript');
748744```
749745
750746Zakł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:
751747
752748``` pascal
753749 fpsystem('osascript -e '#39'tell application "NeoOffice"'#39 +
754750 ' -e '#39'launch'#39' -e '#39'end tell'#39);
755751 {Zwróć uwagę na użycie #39 jako pojedynczego cudzysłowu do parametrów}
756752```
757753
758754Jednak te przykłady są tylko odpowiednikiem następującego polecenia Open (otwórz):
759755
760756``` pascal
761757 fpsystem('open -a NeoOffice');
762758```
763759
764760Podobnie w systemie macOS można emulować polecenia powłoki systemu Windows, aby uruchomić przeglądarkę internetową i uruchomić klienta poczty e-mail za pomocą:
765761
766762``` pascal
767763 fpsystem('open -a safari "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');
768764```
769765
770766i
771767
772768``` pascal
773769 fpsystem('open -a mail "mailto:ss4200@invalid.org"');
774770```
775771
776772co 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:
777773
778774``` pascal
779775 fpsystem('open "http://gigaset.com/shc/0,1935,hq_en_0_141387_rArNrNrNrN,00.html"');
780776```
781777
782778i
783779
784780``` pascal
785781 fpsystem('open "mailto:ss4200@invalid.org"');
786782```
787783
788784Nie zapomnij dołączyć modułu Unix do klauzuli uses, jeśli używasz `fpsystem` lub `shell` (wymiennie).
789785
790786Prawdziwą 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.
791787
792788#### Alternatywy dla Linuksa
793789
794790Chociaż 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).
795791
796792Podobnie 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.
797793
798794### Alternatywy dla funkcji Windows API
799795
800796Wiele 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} ).
801797
802798Na 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.
803799
804800### Kody klawiszy
805801
806802Na szczęście wykrywanie kodów klawiszy (np. w zdarzeniach KeyUp) jest przenośne: patrz [[LCL Key Handling|Obsługa klawiszy LCL]].
807803
808804### Instalowanie swojej aplikacji
809805
810806Zobacz [[Deploying Your Application|Wdrażanie swojej aplikacji]].
811807
812808## Zobacz także
813809
814810- [[Writing portable code regarding the processor architecture|Pisanie przenośnego kodu dotyczącego architektury procesora]]
815811- [[Introduction to platform-sensitive development|Wprowadzenie do rozwoju zależnego od platformy]]
816812- [[Apple-specific UI elements|Elementy interfejsu użytkownika specyficzne dla Apple]]
817813
818814## Linki zewnętrzne
819815
820816- <http://www.midnightbeach.com/KylixForDelphiProgrammers.html> Przewodnik dla programistów Windows zaczynających pracę z Kylix. Wiele pojęć / fragmentów kodu dotyczy Lazarusa.
821817
822818- <http://www.stack.nl/~marcov/porting.pdf> Przewodnik po pisaniu przenośnego kodu źródłowego, głównie pomiędzy różnymi kompilatorami.
823819
824820---
825821*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