gpt4 book ai didi

delphi - 在 ADO 异步回调期间无法将对象添加到 GlobalInterfaceTable

转载 作者:行者123 更新时间:2023-12-03 15:32:51 30 4
gpt4 key购买 nike

我正在使用以下测试代码将对象添加到 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;

一切都很好。该对象位于全局接口(interface)表中,等待被提取。我知道它仍然在那里,因为 TInterfacedObject 中的析构函数尚未运行,例如断点从未命中:

enter image description here

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;

回调返回后,我放入全局接口(interface)表的对象就会被销毁,并命中 TInterfacedObject 中的断点。

实际上,我不会在 ADO 异步回调期间向 GIT 添加虚拟测试对象,i would be adding an actual ADO interface 。但当这不起作用时,我们将失败的代码精简为最基本的代码。

tl;dr:我尝试将一个对象添加到全局接口(interface)表中,但是一旦我将其放入其中,它就会被销毁。

奖金闲聊

我想也许我必须在将对象放入 GIT 之前手动调用 AddRef,但 GIT register 方法会调用 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 中,您也可以从公寓注册在其他公寓中创建的对象。但部分文件的说明有所不同。我仍在努力解决这个问题。

关于delphi - 在 ADO 异步回调期间无法将对象添加到 GlobalInterfaceTable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17429220/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com