4

次のテスト コードを使用して、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はヒットしました。

4

2 に答える 2

1

古いことは知っていますが、オブジェクトを作成してGITに保存する別のスレッド(アプリケーションの終了時にダウンする)で匿名メソッドをスケジュールするだけです。この特別なスレッドのアパートはあなたによって管理され、オブジェクトはそのアパートに住んでいます。

さらに、私のテストから、git では、他のアパートで作成されたオブジェクトもアパートから登録できるようです。しかし、ドキュメントの一部には異なる記載があります。私はまだこれに取り組んでいます。

于 2014-12-03T23:05:04.227 に答える