dll_loader.pas i Access violation w XE3

dll_loader.pas i Access violation w XE3
Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
0

Witam wszystkich.
Tytuł wątku może nie końca przedstawia problem, ale ...
Pytanie kieruję głównie do @olesio, ponieważ wiem, że on tym modułem się też bawił..

A więc, moduł dllloader.pas, służy, między innymi, do tego że możemy używać dllki, które są wkompilowane w zasoby:

Poniższy fragment kodu, działa bez zażaleń:

Kopiuj
var  DLL_Loader : TDLLLoader;
     DLL_Data   : TResourceStream;

......
......
......
  
   DLL_Loader     := TDLLLoader.Create;
   DLL_Data       := TResourceStream.Create(hInstance, 'LIBXML', RT_RCDATA);
   DLL_Loader.Load(DLL_Data);
   DLL_Data.Destroy;

   with DLL_Loader do
   begin
     xmVerXMLLib     := FindExport('xmVerXMLLib');
     ...
     ...
   end;

ALE, działa on prawidłowo w D2007

Niestety w XE3 przy próbie:

Kopiuj
DLL_Loader.Load(DLL_Data);

wyrzuca AV :(

Przetestowałem kilka programów, które korzystają z tego modułu i we wszystkich przypadkach, efekt jest ten sam :(

Czy jest to kwestia, specyficznych ustawień środowiska, czy wina samego modułu?

Wszelkie wskazówki mile widziane..

edytowany 1x, ostatnio: Młody
olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

@Młody: niestety niewiele umiem pomóc. Dla pewności dołaczyłem wrzucany tutaj ostatnio projekt, żeby mieć pewność że dysponujemy takim samym kodem tegoż modułu. Jednak z nagłowka widząć linijkę This DLL Loader code is coyyrighted: (C) 2004, Benjamin Rosseaux, mogę wnioskować, że po prostu sposób działania tego kodu uległ jakiemuś "przedawnieniu". I o ile działał ok pod Delphi 7. I może niektórymi późniejszymi wersjami, których nie sprawdzałem. To od którejś późniejszej wersji po prostu przestał.

Brakuje mi też wiedzy by go udoskonalić oraz by uaktualnić go do prawidłowego działania. A jest to jedyny znany mi kod, który w ogóle był do ogarnięcia i działał. Jedyne co wiem, to raczej nigdy nie miałem przy użyciu tego kodu błędów AV. Testowałem go w sumie raczej tylko z własnymi prostymi dllkami, które na przykład wyświetłały jakiś MessageBox. Oczywiście z bass.dll i bassmod.dll. A także dllką do SQLite 3. Natomiast z innymi nie miałem konieczności. Ogólnie zasada była taka, że być może ze względu na zawiłości systemu, a być może ze względu na bezpieczeństwo, moduł ten nie pozwalał na użycie dllki, która hookowała funkcje WinAPI. Wtedy taki program zachowywał się tak, jakby w ogóle nie korzystał z dodatkowej dllki.

Jedyne co pozostaje, to chyba spróbować nawiążać kontakt z autorem i poprosić go, jeżeli się w ogóle tym jeszcze zajmuje, o poprawienie i zaktualizowanie kodu. Wątpie też, czy ktoś na tym forum miałby ochotę i środowisko plus umiejętności by kod ten dostosować dla wersji Delphi o której wspominasz. Żeby to nawet było komu zlecić. Oczywiście być może istnieją inne rozwiązania, ale ja ich nie znam i korzystałem z tego, ponieważ było dla mnie najbardziej sprawdzone. Nie sprawiało mi problemów pod Delphi 7, o czym już wspominałem. Kiedyś mi o jakiejś alternatywie wspominał zdaje się @Bartosz Wójcik, ale już nie pamiętam co to było. Zdaje się, że chyba był to kod, ktory do Delphi należalo by dopiero przepisać z innego języka.


Pozdrawiam.
edytowany 1x, ostatnio: olesio
Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
0

No nic, będę, coś myślał dalej, w każdym razie, dziękuje za odpowiedź.

A, jeszcze jedno, znalazłem jeszcze, coś takiego:
https://code.google.com/p/duncongames/source/browse/trunk/source/engine/Sound/DLLLoader.pas?r=230

wygląda to na zmodyfikowaną wersję 'naszego' dllloadera i jedno czym się różni (to co na szybko znalazłem)
to zmodyfikowane wywołanie:

Kopiuj
Create

i dodatkową funkcją UnCompressMemory

Kopiuj
być może tu jest haczyk, ale w funkcji <code class="delphi">UnCompressMemory

znajduje się jeszcze jedna funkcja DecompresstoUserBuf

Kopiuj
 która niestety nie jest nigdzie zadeklarowana, przynajmniej ja jej jeszcze nie znalazłem.

Jakbyś miał chwilkę, to może zerknij na to.
edytowany 5x, ostatnio: Młody
TA
  • Rejestracja:ponad 11 lat
  • Ostatnio:około 6 lat
0

@Młody: Nie wiem czy dobrze zrozumiałem co chcesz zrobić, ale sprawdź ten kod:
http://www.delphibasics.info/home/delphibasicssnippets/udllfrommem-loadadllfrommemory

btw. po co robisz takie dziwne kombinacje?

Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
0

Nie do końca kombinacje,
Chodzi o korzystanie z dll, która jest wkompilowana w zasoby exe.

edytowany 1x, ostatnio: Młody
TA
To są kombinacje i proszenie się o kłopoty. MS bez powodu tego nie wspiera.
flowCRANE
A nie możesz po prostu wypakować tej biblioteki z zasobów pliku wykonywalnego i zapisać na dysku, by potem z niej normalnie, dynamicznie załadować potrzebne funkcje?
Młody
Oczywiście, że mogę, i to chyba będzie jedyne rozwiązanie :) Chciałem po prostu znaleźć przyczynę tego błędu :)
flowCRANE
Sam fakt, że biblioteka jest w zasobach jakoś szczególnie mnie nie dziwi, ale dynamiczne jej ładowanie z zasobów, bez zapisu na dysk już trochę dziwi; Nie wiem dlaczego chcesz pominąć zapis dll'ki na dysk, ale to Twój kod i Twój pomysł ;)
Bartosz Wójcik
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 4 lata
  • Postów:439
1

Żadna emulacja ładowania DLL-ek z pamięci zawierających w sobie katalog TLS (czyli 100% tego co robi się w Delphi), bez obsługi TLS-ów nie będzie poprawnie funkcjonować, nie mówiąc o innych strukturatch jak delay import table, poza tym samo inicjalizowanie DLL-ki, jej struktur, flag pamięci etc. to nie wszystko co jest potrzebne do poprawnej obsługi bibliotek ładowanych z pamięci, dochodzą hooki np. na funkcje operujące na wątkach (tak, żeby odpowiednie komunikaty docierały do DllMain), dla bibliotek zawierających manifesty i wymagających specyficznych wersji ładowanych innych DLL-i wymagana jest także obsługa kontekstów aktywacyjnych i większości wypadków sporo hooków na standardowe funkcje WinAPI, żeby taka ładowana z pamięci biblioteka poprawnie funkcjonowała. Jest to wykonalne, ale wymaga sporo siedzenia pod debuggerem i zrozumienia formatu PE i jego struktur.

olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

@Młody: czy możesz potwierdzić że moduł, do którego link podał @Tajiri coś poprawił i działa pod XE3? Bo jeżeli tak, to mamy w razie czego nowsze rozwiązanie na przyszłość.

@Tajiri: pewnie i tak jest, że tego MS nie wspiera i nie do końca to bezpieczne. Ale po co zapisywać coś na dysku, sprawdzać czy już istnieje itp. Jeżeli chcemy mieć wszystko zgrabnie w jednym pliku i na przykład piszemy plugin, który korzysta z bass.dll do odtwarzania nam plików, które ta biblioteka wspiera. Wiadomo, mogą być podejrzenia o chęć stworzenia malware, ale jeżeli nie mamy złych zamiarów to dlaczego nie starać się zrobić czegoś w zgrabniejszej formie niż dostarczać 5 tysięcy dodatkowych plików ;)

@Bartosz Wójcik: za pewne też masz rację, bo masz na ten temat większą wiedzę od nas popartą doświadczeniem. Jednak niby są ograniczenia, a tak wedle mnie złożona dllka jak bass po takim ładowaniu z pamięci problemów nie sprawia. Rozwiązanie jest fajne i wedle mnie kiedy tylko się da mozna z niego korzystać. Na to czy ktoś nie spróbuje zrobić czegoś szkodliwego to już nie za bardzo wpływu nie mamy. Jak wiadomo, z zasobów można i uruchamiać exeki. Ale takie próby są już trakrowane jako bardziej niebezpieczne i wiele programów antywirusowych je wykrywa. Szczególnie kiedy są wykonywane nawet w wątku, zaraz po uruchomieniu aplikacji - "matki".


Pozdrawiam.
TA
W małym programie do użytku własnego można stosować wszystko co przyjdzie nam do głowy, ale w większej aplikacji czy komercyjnym produkcie trzeba unikać (jeśli można) wszystkich trików/hacków/obejść. Swoją drogą nie spotkałem jeszcze apliakcji (nie licząć malwaru i innych tego typu wynalazków), która korzystałaby z ładowania dllek z pamięci.
Bartosz Wójcik
@olesio bass.dll zawiera eksporty, importy i relokacje (właśnie sprawdziłem), nijak się to ma do bibliotek zawierających więcej standardowych struktur, których jak nie obsłużysz to po prostu taki DLL nie będzie Ci działał.
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
2

W tym pliku dllloader.pas który dał w swoim projekcie @olesio (w danym przez @Młody nie sprawdziłem czy to to samo ale pewnie też) aby działało pod Delphi XE5 trzeba zmienić w funkcjach ProcessImports i ProcessExports typy zmiennych odpowiednio Name i FunctionName z PChar na PAnsiChar ma związek z wprowadzonym w nowszych wersjach Delphi UNICODE (po tej zmianie działa chyba we wszystkich wersjach Delphi przynajmniej w Delphi 7 i XE5 na 100%) . Po prostu bez tego z takiego rzutowania jak tam jest na PChar (czyli w nowych wersjach Delphi PWideChar) zamiast nazw funkcji i bibliotek są japońskie krzaki.

@olesio przy okazji w Twoim projekcie masz tam moduł do a_bass_lib_resource.pas tam też masz funkcje niezgodne z nowszymi wersjami Delphi np. PlaySoundFromFile powinna wyglądać tak:

Kopiuj
procedure PlaySoundFromFile(FileName : PChar; LoopSound : boolean);
var
  Looping : integer;
  SoundFileName : PAnsiChar;
begin
  if (LoopSound = True) then
  begin
    Looping := BASS_SAMPLE_LOOP;
  end
  else
  begin
    Looping := 0;
  end;
  {$IFDEF UNICODE}
  SoundFileName := PAnsiChar(AnsiString(FileName));
  {$ELSE}
  SoundFileName := FileName;
  {$ENDIF}
  Chn := BASS_StreamCreateFile(False, SoundFileName, 0, 0, BASS_STREAM_AUTOFREE + Looping);
  BASS_ChannelPlay(Chn, False);
end;

Chyba że Dla Unicode istnieje inna funkcja tego nie wiem bo nie bawiłem się tym BASS.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
edytowany 2x, ostatnio: kAzek
olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Pewnie tak. Dzięki za za zwrócenie uwagi @kAzek. Swoją drogą to kod chyba był kiedyś pisany dla kogoś leniwego na forum, kogo wyręczyłem niestety gotowcem. I jak widać stosowałem wtedy takie "kwiatki", jak (LoopSound = True). Czyli i nawiasy i = True całkowicie zbędne. Ale nie pamiętam od kiedy "nawróciłem się" i uznałem, że stosowanie if not zamiast = False jest jednak przejrzystsze. Mogą być niestety do moich startch postów dołaczone jeszcze źródła z tym niedopracowaniem. Lub posiadając takie na dysku, na szybko je dołączam bez poprawiania.


Pozdrawiam.
flowCRANE
Jeśli już wspominasz o optymalizacji, to warunek także można wykluczyć na rzecz statycznej macierzy indeksowanej typem Boolean; Skoki warunkowe to kosztowne operacje;
Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
0

A więc tak:
@olesio, kodu który podał @Tajiri, nie zdążyłem jeszcze sprawdzić :(
ale po wprowadzeniu zmian do modułu dllloader.pas, które podał @kAzek, wszystko ładnie ruszyło pod XE3 :)

Wielkie dzięki @kAzek.

olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

No to super. Na @kAzek'a zawsze mozemy liczyć. Myślałem, że tutaj ze względu na specyficznośc biblioteki problem będzie bardziej złożony. Swoją drogą. Kiedy jakiś czas temu coś modziłem pod 64 bitowym Lazarusem, to ten zachowywał się tak jakby użycie PChar czy PAnsiChar było mu obojętne. I jakieś pliki z ifdef'ami wszystko traktowały tak jakbym to uruchamiał chyba nadal pod starszymi Delphi. Także nie myśłałem, że tutaj kombinacje ze zmianą typu są potrzebne. Swoją drogą to trochę takie pokręcone. Wiadomo, dla mnie zawsze PChar to PChar, a do Unicode mamy PWideChar. Najlepiej ze względu na wsteczną kompatybilnośc można było tak pozostawić, a nie komplikować ludziom życie. Najważniejsze jednak, że problem rozwiązany.


Pozdrawiam.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
0

Kiedy jakiś czas temu coś modziłem pod 64 bitowym Lazarusem, to ten zachowywał się tak jakby użycie PChar czy PAnsiChar było mu obojętne.

Może nie jest mu to obojętne, ale PAnsiChar to alias typu PChar, więc z koziomu kompilacji jest to to samo; Z resztą w Delphi7 jest tak samo - PAnsiChar to pointer na zwykły Char (nie alias, ale oznacza w praktyce to samo);

I jakieś pliki z ifdef'ami wszystko traktowały tak jakbym to uruchamiał chyba nadal pod starszymi Delphi.

Pewnie miałeś dodaną dyrektywę {$MODE DELPHI}; A dyrektywy {$IFDEF X} powinny działać bez względu na środowisko, chyba że sprawdzałeś np. kompilator, przez {$IFDEF FPC} lub podobne, to kopilacja mogła przebiegać inaczej (no i o to by właśnie chodziło).


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
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)