他人の作ったDLLを簡単に使えるようにコンポーネント化したいのですが、
そのDLLにコールバックして通知する関数を使う際にクラス内の変数が
見えないみたいなのです。
unit uTest;
interface
uses Windows, SysUtils, Classes, ExtCtrls , StdCtrls;
Function TESTLIB(pfnCallback:pointer):Cardinal;
stdcall; external 'TEST.Dll';
type
TTest = class(TObject)
private
FTag : integer;
protected
procedure TestCallback(item:Integer);
public
constructor Create;
destructor Destroy;override;
function Start():boolean;
property Tag : integer read FTag write FTag;
published
end;
implementation
procedure TTest.TestCallback(item:Integer);
begin
Tag:=item; <---このTestのプロパティFTagが拒絶される。
end;
function TTest.Start():boolean;
begin
TESTLIB(addr(TTest.TestCallback));
end;
constructor TTest.Create;
begin
inherited Create;
end;
destructor TTest.Destroy;
begin
inherited Destroy;
end;
過去ログ等色々調べたのですが、うまい解決作が見つかりませんでした。
よろしくお願いします。
コールバック関数の引数にメソッドを渡してるからでは?
>TESTLIB(addr(TTest.TestCallback));
これはクラス定義をポインタにキャストしてるのが間違いであるだけでなく、
もし具体的なインスタンスのメソッドを渡してもダメでしょう。
呼び出された DLL の中からは、Delphi のクラスインスタンスのメソッドへの
コールバックはできません。普通の関数にするしかないです。
>普通の関数にするしかないです。
早速の書き込みありがとうございます。
普通のグローバル?関数のポインターをDLL関数にコールバックポインタとして渡した場合、このクラスを2つ3つと生成した場合の動作はそれぞれが
この一つの関数にコールバックされてしまうのではないのでしょうか?
初歩的な質問で恐縮ですがよろしくご指導ください。
>このクラスを2つ3つと生成した場合の動作はそれぞれが
>この一つの関数にコールバックされてしまうのではないのでしょうか?
そうですね。
implementation
var
test:TTest;
function aCallBack(..)..
begin
test.Somefuncton(..);
end;
のようにしておいて、呼び出す直前に test に self を代入しておくように
する、とかで回避できますね。
うんとさん
ありがとうございました。
目からうろこです。
また、何かありましたらよろしくお願いします。
あれ?
解決したかと思ったのですが、うまく動かないです。
このクラスを複数生成した場合、二つ目を生成した段階で一つ目のコールバックが二つ目のクラスメンバにアクセスしてしまってるのかもしれません。
すみませんうんとさん。
もう一度検証お願いできませんか?
>もう一度検証お願いできませんか?
どのようなコードを書いたのか知りませんので検証できません。
失礼しました。
unit uTest;
interface
uses Windows, SysUtils, Classes, ExtCtrls , StdCtrls;
Function TESTLIB(pfnCallback:pointer):Cardinal;
stdcall; external 'TEST.Dll';
type
TTest = class(TObject)
private
FTag : integer;
protected
procedure TestCallback(item:Integer);
public
constructor Create;
destructor Destroy;override;
function Start():boolean;
property Tag : integer read FTag write FTag;
published
end;
implementation
var tst:TTest;
procedure TTest.TestCallback(item:Integer);
begin
Tag:=item;
end;
procedure aTestCallback(item:Integer);
begin
tst.TestCallback(item);
end;
function TTest.Start():boolean;
begin
tst:=self;
TESTLIB(addr(aTestCallback));
end;
としてみたのですが、どうでしょうか?
で、
>このクラスを複数生成した場合、二つ目を生成した段階で一つ目の
>コールバックが二つ目のクラスメンバにアクセスしてしまってるのかもしれません。
これを試したときのコード、および推論にいたる結果を。
普通に考えると、DLL の中のコードの実行はよびだしたスレッドの内側で
実行されます。複数のインスタンスを作ったとしても、ですから一つの呼び出しの
実行途中で、二つめの呼び出しの実行が割り込むことはあり得ません。
直前に
tst:=self;
を代入してるのですから、コールバック関数から見える tst のインスタンスは
呼び出したインスタンス以外にあり得ません。もちろん、マルチスレッドで
インスタンスごとにスレッドが違っていれば、おっしゃるようなことが起こり得ますが。
ツイート | ![]() |