konwersja dll z x32 na x64

konwersja dll z x32 na x64
MR
  • Rejestracja:prawie 7 lat
  • Ostatnio:14 dni
  • Postów:118
0

mam dll która zawsze była kompilowana jako 32bitowa
Teraz próbuję ją uruchomić na 64 bit.
I co ciekawe.
Jak uruchamiam dll z mojego exeka z Dephi (x64) to program wylicza w takim jednym miejscy wskaźniki 32bitowe.a jak uruchamiam z exeka kompilowanego w .NET (też x64) to w tym samym miejscu już mam adresy 64bitowe

wcześniej było tak:

Kopiuj

PValTablesInfo = ^TValTablesInfo;
  TValTablesInfo = packed record
    Addr1,Addr2:Pointer;
    Size:integer;
    DynArr:boolean;
  end;


New(x);
  x^.Addr1:=Addr1;
  x^.Addr2:=Addr2;
  x^.Size:=Round(Size/4);
  x^.DynArr:=DynArr;
  dataset.FieldByName(FieldName).Tag:=Integer(x);

Generalnie do pola w datasecie podłączam sobie jakiś rekord którego później gdzieś używam na zamknięciu tego dataseta było tak:

Kopiuj
for i:=0 to dataset.FieldCount-1 do
      if (dataset.Fields[i].Tag<>0) then
      begin
      x:=Ptr(dataset.Fields[i].Tag);
      Dispose(x);
      dataset.Fields[i].Tag:=0;
    end;

I to zawsze działało.

natomiast teraz jak przerabiam to na wersję x64 to zamieniłem linię
dataset.FieldByName(FieldName).Tag:=Integer(x);
na
dataset.FieldByName(FieldName).Tag:=Int64(x);

później wysypywał się na
x:=Ptr(dataset.Fields[i].Tag)
więc zmieniłem na
x:=Addr(dataset.Fields[i].Tag);

i tu wszystko wydaje się ok, ale niestety na Dispose(x) wywala Invalid Pointer Operation.

Nie wiem dlaczego.
Poradzicie coś?

edytowany 2x, ostatnio: My Razem
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 11 godzin
0

Może coś pomoże https://docwiki.embarcadero.com/RADStudio/Sydney/en/Converting_32-bit_Delphi_Applications_to_64-bit_Windows
Ogólnie musisz rzutować pointer na liczbę? Czy do taga nie da się czasem zapisać czegokolwiek? Nie możesz tam od razu zapisać po prostu pointer? Podejrzane się wydaje też

x^.Size:=Round(Size/4);

czemu Size / 4? Do czego tego potem używasz? Jeśli to rozmiar wskaźnika to pewnie powinno być Size / 8


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
Marius.Maximus
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 6 godzin
  • Postów:2070
1

A jesteś pewien ze tam powinno byc "Addr(...)" ?
ja bym zrobił tak:

Kopiuj
x:=pointer(dataset.Fields[i].Tag)

--
Nie przyjmuję reklamacji za moje rady, używasz na własną odpowiedzialność.
Programowanie bez formatowania to jak chodzenie ze spodniami spuszczonymi na kostki. Owszem da się ale po pierwsze nie wygodne, po drugie nieprzyzwoicie wygląda.
Przed zaczęciem nowego wątku przeczytam problem XY
Michał Częczek
  • Rejestracja:ponad 2 lata
  • Ostatnio:ponad 2 lata
  • Postów:2
0

Nawet jeżeli jest to kwestia problemów w kodzie to czemu dllka odpalona w delphi x64 jest ciągle ok? Przecież powinny wystąpić podobne problemy

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
0

@Michał Częczek: można wiedzieć po co wrzucasz adresy wskaźników do bazy? Przecież to nie ma prawa działać.

PS: Addr to intrinsic i służy do zwracenia adresu, tak samo jak operator @.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
Michał Częczek
Ja nie wrzucam, ale jestem częściowo zaangażowany w ten problem :) To jakim prawem to działa w procesie deplhpi x64 ale nie w .net x64 ? Czemu te wskaźniki nie rozjeżdżają się tak sam tu i tu ?
obscurity
podejrzewam że delphi nie ma garbage collectora i adresy przy każdym uruchomieniu są takie same, dlatego możesz je sobie zapisać i użyć przy następnym uruchomieniu programu (choć nie jest to zachowanie na którym bym polegał). w c# obiekty się ciągle przemieszczają w pamięci i zapisywanie adresu nawet podczas tego samego uruchomienia nie ma sensu jeśli nie przypniemy obiektu. Nie wiem jak to się ma do wywoływania natywnych bibliotek, ale widocznie może sprawiać problem
Marius.Maximus
:) Ja to założyłem że OP używa tymczasowego TDataset-a w którym z jakiegoś dziwnego powodu chce mieć wskaźniki , opcja że to ma działać po ponownym uruchomieniu to nie masz szans , a jak działa to raczej przypadek. TRZEBA TO PRZEROBIĆ !!!
MR
  • Rejestracja:prawie 7 lat
  • Ostatnio:14 dni
  • Postów:118
0
Adamek Adam napisał(a):

A jesteś pewien ze tam powinno byc "Addr(...)" ?
ja bym zrobił tak:

Kopiuj
x:=pointer(dataset.Fields[i].Tag)

Można i tak, ale używając Addr lub @ mam dostęp do rekordu, którego adres jest w tym tagu, więc to działa i raczej nie jest przyczyną problemu ze zwalnianiem pamięci. Ale oczywiście przetestuję wszystkie sugestie.

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
2
My Razem napisał(a):

natomiast teraz jak przerabiam to na wersję x64 to zamieniłem linię
dataset.FieldByName(FieldName).Tag:=Integer(x);
na
dataset.FieldByName(FieldName).Tag:=Int64(x);

Raczej powinno się pisać kod tak by się kompilował w x64 i x86 bez potrzeby zmieniania za każdym razem. Tutaj powinno chyba być NativeInt(x).

A jeśli coś ci nie działa w .NET to pokaż jak to importujesz w .NET, bo tam jest mnóstwo niuansów.

No i przechowywanie wskaźników pomiędzy uruchomieniami to jest WTF. Zwłaszcza że Microsoft stosuje Address_space_layout_randomization czyli celowe mieszanie wskaźników pomiędzy jednym a drugim uruchomieniem programu tak by utrudniać exploity - raz ustalone wskaźniki się za drugim razem już nie zgadzają. Być może to właśnie zaobserwowałeś.

edytowany 1x, ostatnio: Azarien
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
0

Nie powinno być problemu z wrzuceniem wskaźnika jako liczby do bazy (do rzutowania jest PtrInt), a później odczytania go i zwolnienia bloku pamięci spod adresu, który dana liczba wskazuje. Przykład:

Kopiuj
{$MODE OBJFPC}{$LONGSTRINGS ON}
{$OPTIMIZATION OFF}

type
  PFoo = ^TFoo;
  TFoo = record
    Tag:  Integer;
    Name: String;
  end;
var
  FooAddress: PFoo;
  IntAddress: PtrInt;
begin
  New(FooAddress);
  FooAddress^.Tag  := 16;
  FooAddress^.Name := 'Foo';

  WriteLn('before:');
  WriteLn('  Tag:  ', FooAddress^.Tag);
  WriteLn('  Name: ', FooAddress^.Name, LineEnding);

  IntAddress := PtrInt(FooAddress);
  FooAddress := nil;

  WriteLn('int: 0x', HexStr(IntAddress, SizeOf(IntAddress) * 2));
  WriteLn('foo: 0x', HexStr(PtrInt(FooAddress), SizeOf(FooAddress) * 2), LineEnding);

  FooAddress := Pointer(IntAddress);

  WriteLn('after:');
  WriteLn('  Tag:  ', FooAddress^.Tag);
  WriteLn('  Name: ', FooAddress^.Name, LineEnding);

  Dispose(FooAddress);
end.

Przykładowe wyjście:

Kopiuj
before:
  Tag:  16
  Name: Foo

int: 0x0000000001562830
foo: 0x0000000000000000

after:
  Tag:  16
  Name: Foo

Tak jak @Azarien wspomniał, przy każdym uruchomieniu programu, layout pamięci się zmienia, więc takie triki będą działać jedynie w trakcie danej sesji, a po jej wygaśnięciu (zamknięciu programu), adres znajdujący się w bazie staje się nieaktualny i nie można na nim polegać.

Rzutowanie adresu na liczbę wykorzystuje się np. w funkcjach z Win32 API, do przesyłania wskaźników w parametrach komunikatów np. w funkcji SendMessage (bo te są liczbowe, typu LONG_PTR, czyli PtrInt) wewnątrz programu i tylko w obrębie danej sesji. Przechowywanie tych adresów w formie liczb i wykorzystywanie pomiędzy sesjami jest po prostu niepoprawne i nie ma prawa działać w żadnym nowoczesnym systemie operacyjnym.

Dokładnie to samo można również robić z referencjami obiektów, bo te są zwykłymi wskaźnikami.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 6x, ostatnio: flowCRANE
Michał Częczek
  • Rejestracja:ponad 2 lata
  • Ostatnio:ponad 2 lata
  • Postów:2
0

Wszystkie odpowiedzi skupiają się na wątpliwym przechowywaniu wskaźników w bazie. Niezależnie jak bardzo jest to podejrzane, to nie jest źródłem problemu.
Wersja 32 bitową dllki działa poprawnie zarówno wołana w dotnecie jaki i w aplikacji delhpi. Wersja 64 bitową nie działa tylko w dotnecie x64 a w Delphi x64 działa co wskazuje, że przyczyna problemu jest inna.
Jeśli chodzi o dotneta to dllka tam jest wołana za pomocą P/Invoke (DllImport).

Azarien
Udzieliłem odpowiedzi nieskupiającej się na wskaźnikach: A jeśli coś ci nie działa w .NET to pokaż jak to importujesz w .NET, bo tam jest mnóstwo niuansów.. Bez kodu w C# nie ma co gdybać.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
0

Jedno mnie zastanawia:

My Razem napisał(a):

Jak uruchamiam dll z mojego exeka z Dephi (x64) to program wylicza w takim jednym miejscy wskaźniki 32bitowe.

Co to znaczy „wylicza wskaźniki 32-bitowe” i jak to możliwe, że są 32-bitowe? Nie może tak robić, jeśli DLL jest 64-bitowe. A jeśli jest 32-bitowe, to nie dałbyś rady użyć tej biblioteki z poziomu aplikacji 64-bitowej — bitness musi być jednakowy po obu stronach.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 4x, ostatnio: flowCRANE
SP
SP
  • Rejestracja:prawie 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:181
0

Wyświetl sobie w disassemblerze tą dll, sprawdź sobie w debuggerze jakie są adresy do tych bibliotek załadowanych w pamięci, wyświetl sobie mapę pamięci i zobacz czy są tam te same co w disassemblerze, te instrukcje z dll tzn. czy to ta sama, to samo w C#, prześledź jaki problem, może pod zły adres wskakuje, bo gdzieś indziej relatywny adres został źle obliczony.

Ja kiedyś jak debugowałem sobie własny kernel, to linkier gdzieś przesunął obiekty w pamięci, potem ja je ładowałem jeszcze w jakieś inne miejsce to na końcu gdzieś jakieś relatywne przesunięcie się zgubiło i takim debugowaniem błąd znaleziony w parę minut, a patrząc w kod nie miało się pojęcia gdzie jest błąd.

Nie wiem czemu tak dużo ludzi boi się tych debuggerów, a to najskuteczniejsza broń w walce z błędami.


Knowledge Distiller
MR
  • Rejestracja:prawie 7 lat
  • Ostatnio:14 dni
  • Postów:118
0

Wszyscy chyba źle zrozumieliście że ja przechowuję te wskaźniki w bazie. Przecież tak nie jest. Ja je tylko dołączam do danego pola w datasecie, a nie w bazie.
Na początku do dataseta dodaję wskaźnik, a po jego zamknięciu zwalniam go.
Więc to wszystko dzieje się w ramach jednego wątku.

edytowany 1x, ostatnio: My Razem
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
2

No nie, dobrze zrozumieliśmy, tylko zanim się rozpędzisz i napiszesz sporo kodu wykorzystującego takie cuda, lepiej jest od razu przestrzec Cię, abyś czegoś takiego nie używał, bo to nie jest zbyt bezpieczne, a w dodatku zależne od technologii. Nie miej więc za złe innym, że wyjaśniają dlaczego to zły pomysł. ;)

A wracając do meritum — w Pascalu możesz sobie robić takie rzeczy, bo zarządzanie pamięcią dynamicznie alokowanych leży po stronie programisty. Co zaalokowałeś, musisz sam zwolnić. To prosta zasada, łatwa do ogarnięcia i dająca mnóstwo możliwości i wolności.

Natomiast .NET wykorzystuje GC — jeśli coś stworzysz, przerobisz wskaźnik/referencję na liczbę, a potem przestaniesz używać wskaźnika/referencji, to GC najpewniej zwolni blok (bo już nie jest używany) i Twoja liczba stanie się bezwartościowa. IMO to jest powodem jednoczesnego działania programu w Delphi i niedziałania w .NET, ale nie używam technologii z GC, więc musisz to sobie sam wybadać debuggerem.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
1
My Razem napisał(a):

Wszyscy chyba źle zrozumieliście że ja przechowuję te wskaźniki w bazie. Przecież tak nie jest. Ja je tylko dołączam do danego pola w datasecie, a nie w bazie.
Na początku do dataseta dodaję wskaźnik, a po jego zamknięciu zwalniam go.
Więc to wszystko dzieje się w ramach jednego wątku.

O!
Całkiem brazylijski serial się robi, zaledwie w odc. 2731 wiemy kto jest czyim bratem, choć nadal nie wiemy, czy tego samego ojca/matki

W normalnym języku normalnie użytym bym napisał klasę z pointerem/referencją, ją umieścił w kolekcji ... żadnego rzutowania adresu na integer, co więcej adres w większości języków by był bezpieczny co do typu (tak, wiem, Delphi też posiada te możliwosci, tylko ... myślę sobie ... dlaczego nie sa używane???)

Ale tak to jest, jak zna się tylko zmienne typu TEdit i tablice TDataset (sorry, ale za dużo tego widziałem, również w całkiem wysoko płatnej komercji)

aha, moje streszczenie serialu: jesz zupę widelcem, i stwierdzasz że jedna (krupnik /32b) przynajmniej częściowo daje się jeść, a druga(barszczyk /64b) już nie.

furious programming napisał(a):

No nie, dobrze zrozumieliśmy, tylko zanim się rozpędzisz i napiszesz sporo kodu wykorzystującego takie cuda, lepiej jest od razu przestrzec Cię, abyś czegoś takiego nie używał, bo to nie jest zbyt bezpieczne, a w dodatku zależne od technologii. Nie miej więc za złe innym, że wyjaśniają dlaczego to zły pomysł. ;)

+1
Chore, chore, chore. Nie pierwsze, nie ostatnie, gdzie programista tej platformy sam sobie sterem, żeglarzem i okrętem.


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
edytowany 1x, ostatnio: ZrobieDobrze
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
1
ZrobieDobrze napisał(a):

Chore, chore, chore. Nie pierwsze, nie ostatnie, gdzie programista tej platformy sam sobie sterem, żeglarzem i okrętem.

Nie wiem o którą „platformę” Ci chodzi, ale konieczność/możliwość dbania o większą ilość aspektów związanych z działaniem kodu, nie jest problemem, a zaletą. To nie tylko daje znacznie większą pulę możliwości, ale też uczy dobrych nawyków, w tym myślenia przy pisaniu kodu oraz dbania o każdy jego szczegół.

Pascale, tak samo jak C, są bardzo proste do zrozumienia — możesz nie umieć zbyt dobrze programować, ale patrząc na ich kod widzi się co się dzieje. A kiedy bierze się np. Javę, nie ma się pojęcia jak kod faktycznie działa, bo jest kupą abstrakcji i cukru składniowego — do tego jeszcze GC zarządza pamięcią, więc jest jeszcze trudniej zrozumieć co się dzieje. Nie znając języka, niewiele się zrozumie.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
0
furious programming napisał(a):
ZrobieDobrze napisał(a):

Chore, chore, chore. Nie pierwsze, nie ostatnie, gdzie programista tej platformy sam sobie sterem, żeglarzem i okrętem.

Nie wiem o którą „platformę” Ci chodzi, ale konieczność/możliwość dbania o większą ilość aspektów związanych z działaniem kodu, nie jest problemem, a zaletą. To nie tylko daje znacznie większą pulę możliwości, ale też uczy dobrych nawyków, w tym myślenia przy pisaniu kodu oraz dbania o każdy jego szczegół.

Pascale, tak samo jak C, są bardzo proste do zrozumienia — możesz nie umieć zbyt dobrze programować, ale patrząc na ich kod widzi się co się dzieje. A kiedy bierze się np. Javę, nie ma się pojęcia jak kod faktycznie działa, bo jest kupą abstrakcji i cukru składniowego — do tego jeszcze GC zarządza pamięcią, więc jest jeszcze trudniej zrozumieć co się dzieje. Nie znając języka, niewiele się zrozumie.

Klasyczny proceduralny Pascal jest jest jednym z genialniejszych języków, zresztą nie jedyny ładny język Niklausa Wirtha.
Problemy są dwa:
a) masakra bez trzymanki jaka się dokonał przy wynajdywaniu Object Pascala. Jakieś podejmowanie zagadnień których nie nie potrzebował o galaktykę przed realnym rynkiem, na pograniczu obiektowego / modularnego. Twierdzisz, z e Java jest trudna??? to jaki jest Obect Pascal ???. Problem w Javie nie jest w rdzeniu języka, tylko w dalszym rozwoju (programowanie przez adnotacje, przerośnięte kontenery)
b) dlaczego w real-life w tym ponoć dobrym ekosystemie, komerycjni programiści powołują TEdit zamiast zmienną, zmieną wyłącznie globalną (fabryka tak daje, wiec widocznie tak ma być). Senior prokektu BC++ w którym miałem wspomóc ... KASOWAŁ zmienne lokalne, bo ich nie rozumiał. Odkopiowywał przed wejściem globalną w innej globalnej, żeby ją przywrócić, ale nie był w stanie mentalnie inaczej (facet z naprawde wysokiej półki finansowej)

Może ja mam pecha większego od innych, ale spomiędzy biorących pieniądze za klikanie w Borlandach / Embecadero spotkałem 3/4 autorów koszmarów.
Odpowiem Ci Twoimi słowami: w ogóle nie pojawia się w nich pytanie o zrozumienie języka *). Nie mówię o jednym id... na jakiego bym trafił, ale 2/3-3/4.
W moim ujęciu "ekosystemu języka" zarazem język urabia swoich wyznawców, ale i język jest urabiany pod statystycznie dominującego wyznawcę.
Obrońcy PHP by chcieli przekazać, że v7/v8 radykalnie odnawia styl języka, chciałbym w to wierzyć.
Ale tu jest tylko kontunuacja (z poszerznie runtimów),
... i coraz mniejsza ilość finansujących to musi finansować.

*) jakbym sam miał biegle zrozumieć Object Pascal, i zdać interview o 3 w nocy, to chyba bym się zastrzelił wcześniej. Dlaczego cholera nie mam żadnych problemów z Javą?


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12166
1
ZrobieDobrze napisał(a):

a) masakra bez trzymanki jaka się dokonał przy wynajdywaniu Object Pascala.

Co to jest „masakra bez trzymanki” w kontekście języka programowania? Masz na myśli ręczne zarządzanie pamięcią (brak GC)? No wybacz, ale pamiętanie o zwalnianiu zaalokowanych bloków pamięci jest tak samo naturalne, jak wycieranie zadka po zrobieniu kupy. Jeśli ktoś o tak fundamentalnych czynnościach nie pamięta, to będzie miał… przesrane. :D

Jakieś podejmowanie zagadnień których nie nie potrzebował o galaktykę przed realnym rynkiem, na pograniczu obiektowego / modularnego.

Pascal nie powołał do życia programowania obiektowego (modularnego też nie). Wprowadzenie wsparcia tych paradygmatów było naturalną ścieżką rozwoju języków programowania i odpowiedzią na potrzeby rynku.

Twierdzisz, z e Java jest trudna???

Nie napisałem, że jest trudna, a że często kod pisany w takich językach jak np. Java nie wygląda jak składnia języka programowania, a jak lista magicznych zaklęć Harrego Pottera, których zrozumienie jest niemal niemożliwe bez wertowania dokumentacji.

Problem w Javie nie jest w rdzeniu języka, tylko w dalszym rozwoju (programowanie przez adnotacje, przerośnięte kontenery)

Dokładnie to samo napisałeś w kontekście Pascala.

b) dlaczego w real-life w tym ponoć dobrym ekosystemie, komerycjni programiści powołują TEdit zamiast zmienną, zmieną wyłącznie globalną (fabryka tak daje, wiec widocznie tak ma być). Senior prokektu BC++ w którym miałem wspomóc ... KASOWAŁ zmienne lokalne, bo ich nie rozumiał. Odkopiowywał przed wejściem globalną w innej globalnej, żeby ją przywrócić, ale nie był w stanie mentalnie inaczej (facet z naprawde wysokiej półki finansowej)

Nie ma to jak argumentować swoje stanowisko dowodami anegdotycznymi.

Jeśli będziesz oceniać technologię przez pryzmat jakości kodu produkowanego przez najgorszych ”specjalistów”, to nigdy nie dostrzeżesz prawdziwej jej jakości. To tak jakbyś oceniał jakość samochodu tylko i wyłącznie po stylu jazdy jego użytkownika (w dodatku bardzo kiepskiego użytkownika) — no bez sensu.

Kiedyś też byłem zajawiony na obiektowość, klasy, interfejsy, był hype na generyki, przeładowywanie operatorów, makra i inne coda na kiju. Ale to wszystko bullshit — wiele tych wspaniałych ficzerów tylko mnoży abstrakcje i utrudnia zrozumienie przepływu sterowania. Kilka miesięcy temu zacząłem pracę nad projektem swojej gry, wróciłem do programowania czysto strukturalno-proceduralnego i czuję się jak nowo narodzony — jakbym odkrył programowanie na nowo. Tylko proste funkcje, strukturki i wskaźniki — nic więcej mi do szczęścia nie potrzeba. ;)


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 5x, ostatnio: flowCRANE
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)