次のテスト コードを使用して、GlobalInterfaceTable にオブジェクトを追加しています。
function TForm1.AddSomethingToGit(): DWORD;
var
unk: IUnknown;
cookie: DWORD;
git: IGlobalInterfaceTable;
begin
unk := TCounter.Create;
if FGit = nil then
begin
git := CoGlobalInterfaceTable.Create;
Fgit := git; //yes, i didn't use InterlockedCompareExchange. Can you imagine trying to explain that syntax to people?
end;
OleCheck(Fgit.RegisterInterfaceInGlobal(unk, IUnknown, {out}cookie));
Result := cookie;
end;
そして、ボタン ハンドラーからテスト コードを呼び出します。
procedure TForm1.Button1Click(Sender: TObject);
begin
AddSomethingToGit();
end;
そして、すべてが良いです。オブジェクトはグローバル インターフェイス テーブルに置かれ、抽出されるのを待っています。TInterfacedObject のデストラクタが実行されていないため、まだそこにあることがわかっています。たとえば、ブレークポイントはヒットしません。
注:テスト アプリを今すぐ閉じると、オブジェクトの GlobalInterfaceTable 呼び出しが表示
Release
され、オブジェクトが解放されます。しかし、それはシャットダウン中です。今のところ、私はまだ記憶に残っています。
しかし、ADO コールバックから同じテスト関数を呼び出すと:
conn := CreateTrustedSqlServerConnection(serverName, defaultDatabaseName);
dataSet := TADODataSet.Create(nil);
dataSet.Connection := conn;
dataSet.OnFetchComplete := FetchComplete;
dataSet.CursorLocation := clUseClient;
dataSet.CommandText := 'WAITFOR DELAY ''00:00:03''; SELECT GETDATE() AS foo';
dataSet.CommandType := cmdText;
dataSet.ExecuteOptions := [eoAsyncFetch];
dataSet.Open();
コールバックで:
procedure TForm1.FetchComplete(DataSet: TCustomADODataSet;
const Error: Error; var EventStatus: TEventStatus);
begin
AddSomethingToGit();
end;
グローバル インターフェイス テーブルに配置したオブジェクトは、コールバックが戻るとすぐに破棄され、ブレークポイントに到達しTInterfacedObject
ます。
実際には、ADO 非同期コールバック中にダミーのテストオブジェクトを GIT に追加するのではなく、実際の ADO インターフェイスを追加します。しかし、それがうまくいかないときは、失敗したコードを必要最小限にまで切り詰めます。
tl;dr : グローバル インターフェイス テーブルにオブジェクトを追加しようとしましたが、そこに置くとすぐに破棄されます。
ボーナスおしゃべり
オブジェクトを GIT に配置する前に手動で呼び出さなければならないと思っAddRef
たのですが、GIT登録メソッドはAddRef
それ自体を呼び出します。
の構築方法IGlobalInterfaceTable
:
class function CoGlobalInterfaceTable.Create: IGlobalInterfaceTable;
begin
// There is a single instance of the global interface table per process, so all calls to this function in a process return the same instance.
OleCheck(CoCreateInstance(CLSID_StdGlobalInterfaceTable, nil, CLSCTX_INPROC_SERVER, IGlobalInterfaceTable, Result));
end;
インターフェイスの(私のではない)Delphi翻訳を使用:
IGlobalInterfaceTable = interface(IUnknown)
['{00000146-0000-0000-C000-000000000046}']
function RegisterInterfaceInGlobal(pUnk: IUnknown; const riid: TIID; out dwCookie: DWORD): HRESULT; stdcall;
function RevokeInterfaceFromGlobal(dwCookie: DWORD): HRESULT; stdcall;
function GetInterfaceFromGlobal(dwCookie: DWORD; const riid: TIID; out ppv): HRESULT; stdcall;
end;
そして完全を期すために:
const
CLSID_StdGlobalInterfaceTable : TGUID = '{00000323-0000-0000-C000-000000000046}';
アップデートワン
誰かが私のオブジェクトが台無しにされたと思われるのではないかと恐れて、私は必死に自分のオブジェクトを追加することを避けたかった. そのため、もともと私は Delphi の組み込みの を使ってデモを行いましたTInterfacedObject
。破棄されているのが本当に「私の」オブジェクトであることを確認するために、質問の参照を からTInterfacedObject
に変更しましたTCounter
。
TCounter = class(TInterfacedObject, IUnknown)
private
FFingerprint: string;
public
constructor Create;
destructor Destroy; override;
end;
{ TCounter }
constructor TCounter.Create;
begin
inherited Create;
FFingerprint := 'Rob Kennedy';
end;
destructor TCounter.Destroy;
begin
if FFingerprint = 'Rob Kennedy' then
Beep;
inherited;
end;
そして、私TCounter.Destroy
はヒットしました。