Rozpoznanie własnej klasy w procedurze z Bpl

0

Zdefiniowałem w unicie dodanym do Bpl klasę i metodę:

type
 TBaseTest = class
  private
  public
  end;

implementation

procedure ClassTest(test: TObject); stdcall;
begin
 if test is TBaseTest
  then ShowMessage('To jest klasa typu TBaseTest')
   else ShowMessage('To NIE jest klasa typu TBaseTest'+#13+
                    'ponieważ jest to klasa typu '+test.ClassName);
end;

exports ClassTest name 'ClassTest';

a następnie (po załadowaniu Bpla) wywołuję ją z aplikacji:

var
 myTest: procedure (test: TObject); stdcall;
 myTestObject: TBaseTest;
begin
//.....
@myTest := GetProcAddress(myHandle,'ClassTest');
   if (@myTest <> nil) then
    begin
     myTestObject := TBaseTest.Create;
     myTest(myTestObject);
     FreeAndNil(myTestObject);

i niestety metoda nie rozpoznaje typu klasy (if test is TBaseTest) mimo, że test.ClassName wyświetla nazwę prawidłowo. Oczywiście jak badam standartowa klase Delphi np. TForm, TButton wszystko jest w porządku. Gdzie popełniam bład?

dodanie znaczników <code class="delphi"> - Furious Programming

1

Jeżeli instancja klasy nie została stworzona w DLL-ce (czy tam BPL - zasada działania jest podobna) (a tak nie jest, ponieważ TBaseTest.Create wywołujesz już w programie), operator is jej nie wykryje.

0

Ogólnie rzecz biorąc taki myk nie przejdzie, dlatego że najpewniej (bo nie podałeś) obie klasy mają różne wnętrze; W bibliotece masz deklarację pustej klasy, a w programie już pewnie klasa pusta nie jest; Natomiast operator Is nie sprawdza jedynie nazwy klasy - to nieco bardziej skomplikowana operacja; To pewnie nawet nie przejdzie w przypadku, gdy zarówno w programie jak i bibliotece zadeklarujesz dokładnie takie same klasy z dokładnie taką samą zawartością (niczym copy-paste z programu do biblioteki);

Podobna sytuacja jest z typami prostymi zadeklarowanymi w dwóch modułach tego samego programu; Pomimo tego, że ich deklaracje będą wyglądać identycznie, nie będziesz mógł wykorzystać tego z pierwszego modułu w drugim module, bo kompilator zgłosi niezgodność typów;

Podsumowując - jeśli Twój bpl nie zna klasy z programu - raczej nie ma możliwości tego wykonać; Rozwiązaniem może być wykorzystanie jednego modułu z deklaracją klasy zarówno w programie, jak i w bplu, ale musiałbyś to sprawdzić (to tylko podejrzenie).

0
procedure ClassTest<T>(test: TObject); stdcall;
begin
   if test is T then ...
end;

czy takei coś ma szanse zadziałać?

0

@TLesiu:
Co? Jak? Po co? Dlaczego? ...
Powinno się skompilować, ale nie ma szansy na zadziałanie (w kontekście postu autora).
Po rozwinięciu typu przez kompilator otrzymasz tak czy siak if (test is TBaseTest) then, więc wychodzi na jedno.

0

@MarekKolman - a w jaki sposób porównujesz np. klasy TForm czy TButton, że je poprawnie rozpoznaje?

0
furious programming napisał(a):

Podsumowując - jeśli Twój bpl nie zna klasy z programu - raczej nie ma możliwości tego wykonać; Rozwiązaniem może być wykorzystanie jednego modułu z deklaracją klasy zarówno w programie, jak i w bplu, ale musiałbyś to sprawdzić (to tylko podejrzenie).

Zarówno do bpl'a jak i do programu był podłączony ten sam unit z deklaracjami klas lecz to nie pomaga w rozwiazaniu problemu. Myślę że masz dużą rację pisząc "Natomiast operator is nie sprawdza jedynie nazwy klasy..." bo to fakt o którym zapomniałem :)

0

Nie wiem co konkretnie chcesz osiągnąć ale chyba możesz coś takiego masz moduł:

unit uTest;

interface

type
  TBase = class
  public
    function JakasFunkcja: Integer; virtual; abstract;
  end;

implementation

end.

Zawiera on deklarację klasy natomiast metody, właściwości itd... są niezaimplementowane ten moduł jest zarówno w BPL jak i programie.
W BPL dodatkowo implementujesz klasę dziedziczącą po TBase a także eksportujesz funkcję tworzącą tą klasę:

unit uBPL;

interface
uses
  uTest;

type
  TBaseTest = class(TBase)
  public
    function JakasFunkcja: Integer; override;
  end;

implementation


function TBaseTest.JakasFunkcja: Integer;
begin
  result:= 10;
end;

function CreateClass: TBaseTest; stdcall;
begin
  result:= TBaseTest.Create;
end;

function ClassTest(AObject: TObject): Boolean; stdcall;
begin
 if AObject is TBase then
   result:= True
 else
   result:= False;
end;

exports CreateClass name 'CreateClass',  ClassTest name 'ClassTest';

end.

Natomiast w programie możesz wywołać procedurę i utworzyć obiekt nawet używać jego metod pomimo że są one zaimplementowane tylko w BPL:

var
  hLib: Cardinal;
  pCreateClass: function: TBase; stdcall;
  pClassTest: function(AObject: TObject): Boolean; stdcall;
  myTestObject: TBase;
begin
  hLib:= LoadPackage('TestBPL.bpl');
  try
  pCreateClass:= GetProcAddress(hLib,'CreateClass');
  if Assigned(pCreateClass) then
  begin
    pClassTest:= GetProcAddress(hLib,'ClassTest');
    if Assigned(pClassTest) then
    begin
      myTestObject:= pCreateClass;
      if pClassTest(myTestObject) then
        ShowMessage(IntTostr(myTestObject.JakasFunkcja));
      FreeAndNil(myTestObject);
    end;
  end;
  finally
  UnloadPackage(hLib);
  end;
end;
0

a nie mozna tego przez interface zrobic?

 
IMyClassInterface = interface(IInvokable)
[GUID = generowanie Ctrl+Shift+G

  function DoSomething: OleVariant; safecall;
end

i po stornie dll implmentacja klasy. Metoda exportujaca np

function ObjectFromDll: IMyClassInterface; safecall;

a rozpoznanie czy jest danej klasy to sprawdzenie czy implementuje dany interface.

BTW. operator is sprawdza tez cos co sie nazywa ControlAtom. Sa rozne - dlatego delphi przeszlo na bpl zamiast dll.

0
crowa napisał(a):

rozpoznanie czy jest danej klasy to sprawdzenie czy implementuje dany interface.

Czy jest mozliwe (Delphi 7) sprawdzenie czy dana klasa implementuje interfejs uzywając operatora is?

0

nie sprawdza sie tego czy dana klasa implementuje interface przez is.
Uzyj supports

1

Interfejsy są po to, aby wiedzieć, a nie aby sprawdzać. Jeśli chcesz sprawdzać interfejs, to masz błąd projektowy.

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