我使用以下测试代码将对象添加到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中的析构函数尚未运行,例如断点从未命中:
Note: if i close the test app right now, then i will see the GlobalInterfaceTable call
Release
on my object, freeing it. But that’s during shutdown, for now i’m still in memory.
但是如果我从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异步回调i would be adding an actual ADO interface期间向GIT添加一个虚拟测试对象.但是当这不起作用时,我们将失败的代码修剪为简单的代码.
tl; dr:我尝试将一个对象添加到全局接口表中,但是只要我把它放在那里就会被销毁.
奖金Chatter
我想也许我必须在将对象放入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被击中了.
最佳答案 我知道它已经过时了,但是您可以在另一个线程(将在应用程序的出口处下移)中安排一个匿名方法,您可以在其中创建对象并将其存储到GIT中.就像那个特殊线程的公寓将由你管理,对象将住在那个公寓里.
不过,从我的测试中可以看出,在git中你也可以在公寓里注册其他公寓中创建的物品.但部分文件的说法不同.我还在努力.