dll_loader.pas i Access violation w XE3

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ń:

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:

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

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.

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:

Create

i dodatkową funkcją UnCompressMemory

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

znajduje się jeszcze jedna funkcja DecompresstoUserBuf

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

Jakbyś miał chwilkę, to może zerknij na to.
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?

0

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

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.

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".

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:

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.

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.

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.

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.

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

1 użytkowników online, w tym zalogowanych: 0, gości: 1