环境是Delphi XE2 Enterprise。
与use dispInterface in Delphi with no classid有关。重新发布作为一个不同的问题,因为我已经远远超出以前的问题(感谢@EricBrown),现在有一个更具体的问题。
我有一个带有COM接口的.NET dll,我已在计算机上注册并作为类型库导入Delphi。我正在使用Delphi创建的tlb.pas文件。
使用我在IDispatch接口和TAutoIntf后代类中实现的几个dispInterface,我已成功初始化了我需要将COM接口中的方法调用到.NET库的类和接口。以下是一些用于说明声明/实现的代码:
// COM Event Sink GUID
DIID_IResponseListener: TGUID = '{ABC29F08-B628-4747-BA9E-469D408E57B9}';
// *********************************************************************//
// DispIntf: IResponseListener
// Flags: (4096) Dispatchable
// GUID: {ABC29F08-B628-4747-BA9E-469D408E57B9}
// *********************************************************************//
IResponseListener = dispinterface
['{ABC29F08-B628-4747-BA9E-469D408E57B9}']
procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); dispid 1610744833;
procedure RequestFailed(const requestID: WideString; const error: WideString); dispid 1610744834;
procedure TablesUpdates(const responseObj: IResponse); dispid 1610744835;
end;
...my implementation:
IFXResponseListener = interface(IDispatch)
['{3204D3F7-5DF2-4470-89D5-D34F4F6F0381}']
procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); dispid 1610744833; safecall;
procedure RequestFailed(const requestID: WideString; const error: WideString); dispid 1610744834; safecall;
procedure TablesUpdates(const responseObj: IResponse); dispid 1610744835; safecall;
end;
TFXResponseListener = class(TAutoIntfObject,IFXResponseListener)
private
FDisp: IDispatch;
FResp: IResponse;
function GetResponseListIntf: IResponseListener;
public
constructor Create;
destructor Destroy;
published
procedure RequestCompleted(const requestID: WideString; const responseObj: IResponse); safecall;
procedure RequestFailed(const requestID: WideString; const error: WideString); safecall;
procedure TablesUpdates(const responseObj: IResponse); safecall;
property ResponseObj: IResponse read FResp;
property ListenerDispIntf: IResponseListener read GetResponseListIntf;
end;
...
{ TFXResponseListener }
constructor TFXResponseListener.Create;
var
TypeLib: ITypeLib;
begin
OleCheck(LoadRegTypeLib(LIBID_fxcore2_com,fxcore2_comMajorVersion,fxcore2_comMinorVersion,0,TypeLib));
inherited Create(TypeLib,DIID_IResponseListener);
end;
destructor TFXResponseListener.Destroy;
begin
inherited;
end;
function TFXResponseListener.GetResponseListIntf: IResponseListener;
begin
FDisp := Self as IFXResponseListener;
FDisp._AddRef;
Result := IResponseListener(FDisp);
end;
procedure TFXResponseListener.RequestCompleted(const requestID: WideString; const responseObj: IResponse);
begin
showmessage('Completed: ' + requestID);
FResp := responseObj;
end;
procedure TFXResponseListener.RequestFailed(const requestID: WideString; const error: WideString);
begin
showmessage('Failed: ' + requestID);
end;
procedure TFXResponseListener.TablesUpdates(const responseObj: IResponse);
begin
showmessage('TablesUpdates');
end;
这是我尝试使用界面的地方:
FRespList := TFXResponseListener.Create;
try
FSess.subscribeResponse(FRespList.ListenerDispIntf);
except
// errors out here with 'The parameter is incorrect'
end;
将其追溯到System.Win.ComObj的内容,在第1793行,它调用:
Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind, DispParams, Result, @ExcepInfo, nil);
此时,DispID参数有效(1610743816),GUID_NULL为'(0,0,0,(0,0,0,0,0,0,0))',InvKind为'1 ',DispParams是'($ 2152FE8,零,1,0)',结果是'$ 12FE24',@ ExcepInfo是'$ 12FDE0'。
在System.pas第30133行中,TInterfacedObject.QueryInterface被调用两次。在第二次运行时,它返回结果'E_NOINTERFACE',并显示可怕的'参数不正确'消息。
我真的不确定从哪里开始,但我希望COM专家和/或Delphi专家可以对此进行审核,看到有些不妥。
我也想知道是否存在.NET框架版本或其他问题。我正在使用框架版本4.5.1;不确定如何确定.NET程序集是否适用于此版本的框架,或者它是否真的需要早期版本。
非常感谢任何相关的.NET / COM调试技术。
另请注意,我可以使用不同的dispinterface / IDispatch / TAutoIntfObj后代类和类似的调用复制此问题,与'T'相同。
感谢。
答案 0 :(得分:0)
看起来这个就在包里。感谢@EricBrown和@RemyLebeau,我能够让它发挥作用。
Remy建议改变FRespList的实例化:
var
FRespList: TFXResponseListener;
为:
var
FRespList: IFXResponseListener;
......做了伎俩。所以当我使用
进行实例化时FRespList := TFXResponseListener.Create;
......我得到了正确的结果,一切都变得肥胖,愚蠢和快乐。
另外我需要指出的是,分配给dispinterface的GUID必须用于我创建的IDispatch接口后代,否则,我们将返回'参数不正确'。不知道是否在某处记录了......
也有点奇怪,当我完成了我的IDispatch后代时我就没有了。这会将TAutoIntfObject后代的引用计数减少到 2 。这导致内存泄漏。我测试并尝试了不同的东西来使这个引用到dec,最后不得不做一些奇怪的事情:
**procedure** TMyClass.Destroy; // <- changed from **destructor** TMyClass.Destroy;
begin
inherited Destroy; // <- had to call this first!
// then...
while Self.RefCount > 0 do
IUnknown(Self)._Release;
end;
...然后调用MyClassInstance.Destroy;在没有AV或内存泄漏的情况下让课程自由。
如果有人知道为什么我有3个引用我的类,为什么FreeAndNil(MyClassInstance)和IMyClass:= Nil;因为访问冲突和/或内存泄漏留下了引用2的引用,为什么我必须首先销毁继承,为什么我必须将类作为IUnknown进行类型转换并手动释放实例,请说出来。
在另一个接口/类对上,我仍然从TServerEventDispatch获得内存泄漏。这是Delphi在tlb.pas文件中自动创建的类之一。如果有人有建议......
COM ...你必须爱它!
我想向Eric Brown和Remy Lebeau提出任何要点,但我不知道如何。
所以...感谢GUYS!