Parametry dla procedury wywołanej dynamicznie z DLL

0

W jaki sposób zadeklarować procedure z parametrami wywoływaną dynamicznie z biblioteki DLL ?

To przykład z artykułu...

var
  DLL: THandle;
  WczytajCos: procedure;
begin
  DLL := LoadLibrary('biblioteka.dll');
  try
    @WczytajCos := GetProcAddress(DLL, 'WczytajCos');
    if @WczytajCos <> nil then WczytajCos;
  finally
    FreeLibrary(DLL);
  end;
end;

A jak zadeklarować, jeśli procedura miała by parametry ?

  WczytajCos(Parametr1: String);

Jeśli wywołam tak, mam Access Violation przy linii if@WczytajCos <> nil then ...

type
 TWczytajCosP = procedure (Forma: TForm; Plik: String);
var
 DLL: THandle;
 WczytajCos: TWczytajCosP;
begin
  DLL := LoadLibrary('biblioteka.dll');
  try
    @WczytajCos := GetProcAddress(DLL, 'WczytajCos');
    if @WczytajCos <> nil then WczytajCos(Form1, ExtractFilePath(Application.ExeName) + 'dane.txt');
  finally
    FreeLibrary(DLL);
  end;
end;

W bibliotece DLL takie wywołanie

library lib1;

uses
  Forms, Dialogs;

procedure WczytajCos(Forma: TForm; Plik: String); stdcall;
begin
 ShowMessage(Forma.Name + ' | Plik: ' + Plik);
end;

exports
 WczytajCos;
end.
0

śmiem twierdzić, że AV jest z całkiem innego powodu - daj kod całej biblioteki i dpr'a

0
Misiekd napisał(a)

śmiem twierdzić, że AV jest z całkiem innego powodu - daj kod całej biblioteki i dpr'a

Podałem wcześniej edytując posta 27minut przed Twoją odpowiedzią.

0

to gdzie do kur*** nędzy jest wypisany wielkimi literami w komentarzu SHAREMEM!!!!!!
Wszędzie trąbią NIE PRZEKAZYWAĆ DO DLLa OBIEKTÓW, STRINGÓW I WSZYSTKIEGO CO NIE JEST TYPEM PROSTYM, ale nie.

Sorki Opi za opierdziel ale wydaje mi się, że jesteś na tyle dobrym programistą, że takie błędy mógłbyś sobie darować

0

Owszem, ale zamiast tego stosuje ShortString;

Jednak błąd już znalazłem i NIE DOTYCZYŁ ON "STRING" !!

Zabrakło "stdcall" dokładnie w tym miejscu

type
 TWczytajCosP = procedure (Forma: TForm; Plik: String); stdcall;
0

ta a Form1 przekazywany do dll to co to jest int, double czy może pchar :>

0

Ja zalecam unikanie stosowania ShareMem. Bo jeśli ktoś napisze Ci dllkę w innym języku niż Delphi, to raczej dupa.

Nie przekazuj stringów - shortStringi, lub lepiej PChar
Nie przekazuj obiektów - tylko wskaźniki do nich - to samo tyczy się rekordów.

Jak deklarujesz z parametrami? No to chyba jest w artykule tutaj na stronie:

var
  mojaProcka: procedure(Param1: PChar; Param2: integer);
  mojaFunkcja: function: boolean; //oczywiście możesz dodać parametry

Pamiętaj, że musisz mieć IDENTYCZNIE zadefiniowaną funkcje w aplikacji, co w DLL.

AV u Ciebie jest spowodowane tym, że zadeklarowana procedura w programie i DLL się różnią.

Jeśli w DLL masz:

procedure WczytajCos(p: PChar; Form: PForm);
//gdzie PForm jest wskaźnikiem na TForm

to w aplikacji musisz mieć:

var
  wczytajCos: procedure(p: PChar; Form: PForm); //oczywiście nazwa zmiennej nie musi być taka :)
0

Dzięki Juhas

Misiekd napisał(a)

ta a Form1 przekazywany do dll to co to jest int, double czy może pchar :>

Przecież podane, że TForm.
Ale czy musi to być wskaźnik ? Bez wskaźnika (podałem TForm) i jest dobrze (nie ma błędów AV). Wyłapuje błędy w EurekaLog.

A String zastosowałem chwilowo (jakie, oprócz kompatybilności, wady ma String w DLLce ?), stosuję ShortString, gdyż PChar mi nie pasuje.

0

Opi czy Ty jakiś przytępiony dzisiaj jesteś czy co?? TForm to KLASA, Form1 to OBIEKT, a takich do dllki się nie przekazuje.

0

:) :P nie mam pojęcia...

Ale próbuje zrobić wersję językową.
Wywołuje w programie z parametrami procedure do DLLki, które zmienia język komponentom.

W procedurze podaje nazwę formy, która ma zostać przeszukana i znalezionym komponentom przypisać inny tekst...

więc mówisz, że się tak nie da ?

0

Udaje się, ale nie do końca...

Domyślnie jeśli jest tak:

procedure TFormP1.B2Click(Sender: TObject);
var
 DLL: THandle;
 WczytajJezykForma: procedure (Forma: TForm; PlikJezyka: ShortString); stdcall;
begin
  DLL := LoadLibrary(pChar(ExtractFilePath(Application.ExeName) + 'images.dll'));
  try
    @WczytajJezykForma := GetProcAddress(DLL, 'WczytajJezykForma');
    if @WczytajJezykForma <> nil then WczytajJezykForma(FormP1, ExtractFilePath(Application.ExeName) + 'Polski.lng');
  finally
    FreeLibrary(DLL);
  end;
end;

i jest dobrze,

Kiedy przekażę "Forma" jako TForma = TForm:

procedure TFormP1.B2Click(Sender: TObject);
type
 TForma = TForm;
var
 DLL: THandle;
 WczytajJezykForma: procedure (Forma: TForma; PlikJezyka: ShortString); stdcall;
begin
  DLL := LoadLibrary(pChar(ExtractFilePath(Application.ExeName) + 'images.dll'));
  try
    @WczytajJezykForma := GetProcAddress(DLL, 'WczytajJezykForma');
    if @WczytajJezykForma <> nil then WczytajJezykForma(FormP1, ExtractFilePath(Application.ExeName) + 'Polski.lng');
  finally
    FreeLibrary(DLL);
  end;
end;

to nie ma przekazania nazwy Formy.

Chyba dzisiaj dam sobie spokój ;-)

0

Jeszcze raz. Czego nie można robić:

  • Stosować jako parametrów STRINGÓW. Jest to związane z pamięcią i jeśli przekażesz string jako parametr, to dllka będzie szukała go w zupełnie innym obszarze pamięci - tam, gdzie go nie ma albo nawet nie ma nic(tak skrótowo).

  • Stosować jako parametrów OBIEKTÓW. Jest to związane z pamięcią i jeśli przekażesz obiekt jako parametr, to dllka będzie szukała go w zupełnie innym obszarze pamięci - tam, gdzie go nie ma albo nawet nie ma nic(tak skrótowo).

  • Stosować jako parametrów REKORDÓW. Jest to związane z pamięcią i jeśli przekażesz rekord jako parametr, to dllka będzie szukała go w zupełnie innym obszarze pamięci - tam, gdzie go nie ma albo nawet nie ma nic(tak skrótowo).

Aby przekazać jakiś dłuższy tekst(ShortString to tylko 255 znaków) - stosuj PChar.
Jeśli chcesz w dllce operować na jakimś obiekcie(np. na formie ze swojej aplikacji i jej komponentach) - przekazuj jako wskaźnik do swojej formy. To samo tyczy się rekordów.

Tylko pamiętaj, że zwykła forma(klasa TForm) nie ma nic Twojego.
Ty robiąc cokolwiek w projekcie, tworzysz własną klasę(nawet pewnie o tym nie wiesz ;)), która dziedziczy po TForm.

Wniosek z tego taki, że jeśli będziesz chciał przekazywać wskaźnik do formy, musi to być wskaźnik do TWOJEJ formy.
Czyli np:

type
  PMojaForma: ^TMojaForma; //w żadnym wypadku: ^TForm;
0

Juhas, ale czegoś tu nie rozumiem...

Dlaczego Ten przykład z Językiem działa, skoro nie można przekazać TForm ?

http://94.72.120.233:1000/Jezyk%20z%20DLL.rar

0
Opi napisał(a)

Juhas, ale czegoś tu nie rozumiem...

Dlaczego Ten przykład z Językiem działa, skoro nie można przekazać TForm ?

http://94.72.120.233:1000/Jezyk%20z%20DLL.rar

Nie chce mi się tego analizować ;)
Ale jeśli Ci działa to:

  • albo masz niezwykłego farta
  • używasz ShareMem(tudzież innego managera pamięci)
  • coś innego.

W każdym razie oczywiście jest to złe :)

0

Juhas, pobierz póki udostępniam na serwerze...

Poza tym nie używam ShareMem.
Kod jest krótki i jego analiza nie zajmie dłużej niż 2 minuty.

0
Opi napisał(a)

Juhas, pobierz póki udostępniam na serwerze...

Poza tym nie używam ShareMem.
Kod jest krótki i jego analiza nie zajmie dłużej niż 2 minuty.

Nie ma :)
Zresztą naprawdę nie chce mi się analizować czyjegoś kodu. Jest tak, jak piszemy.
Akurat, że tu działa, to źle ;)

0
Juhas napisał(a)

Nie ma :)
Zresztą naprawdę nie chce mi się analizować czyjegoś kodu. Jest tak, jak piszemy.
Akurat, że tu działa, to źle ;)

Już usunięte... trudno.

Akurat, że tu działa coś znaczy... możliwe, że Tobie chodzi, aby DLL była zgodna z innymi językami programowania, ale jeśli używa się jej tylko i wyłącznie w programie swoim napisanym w Delphi to nie musi być to zgodne z przyjętymi zasadami ogólnymi bibliotek.

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