Delphi [weak]引用属性在多个库中执行时产生“无效类typecast”
德尔福柏林10.1增加了[弱]参考.
Marco Cantu’s Blog有一些基础.
对于我的测试,我创建了两个拥有两个自动化对象类型的COM库.容器对象保存内容对象的列表,而内容对象持有对其容器的弱引用. 以下两种情况进行了测试和正常工作(弱引用设置为null并释放内存): >具有接口和CoClasses的单个COM库. 但是,当我将coclasses放在两个独立的库中时,代码会产生“无效的类型转换”,当删除[weak]属性时,该错误消失.请原谅这个奇怪的样本,其目的只是为了使问题变得最小,不能作为标准编码习惯 这是第一个定义两个接口的库.ridl文件,同时定义了CoClass [ uuid(E1EE3651-A400-49BF-B5C5-006D9943B9C0),version(1.0) ] library DelphiIntfComLib { importlib("stdole2.tlb"); interface IMyContainer; interface IMyContent; coclass MyContainer; [ uuid(A7EF86F7-40CD-41EE-9DA1-4D9B7B24F06B),helpstring("Dispatch interface for MyContainer Object"),dual,oleautomation ] interface IMyContainer: IDispatch { [id(0x000000C9)] HRESULT _stdcall Add([in] IMyContent* AMyContent); }; [ uuid(BFD6D976-8CEF-4264-B95A-B5DA7817F6B3),helpstring("Dispatch interface for MyContent Object"),oleautomation ] interface IMyContent: IDispatch { [id(0x000000C9)] HRESULT _stdcall SetWeakReferenceToContainer([in] IMyContainer* AContainer); }; [ uuid(1F56198B-B1BE-4E11-BC78-0E6FF8E55214) ] coclass MyContainer { [default] interface IMyContainer; }; }; 这是我的容器实现 unit Unit1; {$WARN SYMBOL_PLATFORM OFF} interface uses ComObj,ActiveX,DelphiIntfComLib_TLB,StdVcl,Generics.Collections; type TMyContainer = class(TAutoObject,IMyContainer) private FList: TList<IMyContent>; protected procedure Add(const AMyContent: IMyContent); safecall; public Destructor Destroy; override; procedure Initialize; override; end; implementation uses ComServ; procedure TMyContainer.Add(const AMyContent: IMyContent); begin FList.Add(AMyContent); AMyContent.SetWeakReferenceToContainer(self); end; destructor TMyContainer.Destroy; begin FList.Free; inherited; end; procedure TMyContainer.Initialize; begin inherited; FList := TList<IMyContent>.create; end; initialization TAutoObjectFactory.Create(ComServer,TMyContainer,Class_MyContainer,ciMultiInstance,tmApartment); end. 我的第二个库引用第一个,只包含我的内容界面的CoClass [ uuid(65659EE4-1949-4112-88CA-F2D5B5D8DA2C),version(1.0) ] library DelphiImplComLib { importlib("stdole2.tlb"); importlib("DelphiIntfComLib.dll"); coclass MyContent; [ uuid(79D1669A-8EB6-4AE6-8F4B-91137E6E6DC1) ] coclass MyContent { [default] interface IMyContent; }; 其实施与弱参考 unit Unit2; {$WARN SYMBOL_PLATFORM OFF} interface uses ComObj,DelphiImplComLib_TLB,DelphiIntfComLib_TLB; type TMyContent = class(TAutoObject,IMyContent) private [Weak] //If included will cause "invalid class typecast" error FContainer : IMyContainer; protected procedure SetWeakReferenceToContainer(const AContainer: IMyContainer); safecall; end; implementation uses ComServ; procedure TMyContent.SetWeakReferenceToContainer(const AContainer: IMyContainer); begin FContainer := AContainer; end; initialization TAutoObjectFactory.Create(ComServer,TMyContent,Class_MyContent,tmApartment); end. 我测试如下 program Project13; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils,DelphiImplComLib_TLB in 'implDelphiImplComLib_TLB.pas',DelphiIntfComLib_TLB in 'IntfDelphiIntfComLib_TLB.pas'; var GMyContainer : IMyContainer; GMyContent : IMyContent; begin GMyContainer := CoMyContainer.Create; GMyContent := CoMyContent.Create; GMyContainer.Add(GMyContent); end. 为什么我在分割实现时遇到错误?如何缓解这个问题? 解决方法
正如Allen Bauer在答案中解释的那样,[weak]不支持COM接口,因为它们不能保证由Delphi TObject派生类支持,这对于[weak]引用在对象被自动删除时是必需的被释放RTL在运行时跟踪弱引用,但不能跟踪库之间的弱引用,除非RTL库的单个实例在它们之间共享(即,如果您使用启动运行时软件包编译库,然后使用可执行文件部署RTL BPL ).
但是,只要不需要使用[weak]的自动修改功能,可以使用无类型的指针: type TMyContent = class(TAutoObject,IMyContent) private FContainer : Pointer{IMyContainer}; ... end; 只要您需要使用其方法/属性,就必须将FContainer类型转换为IMyContainer,例如: IMyContainer(FContainer).Add(...); 在10.1及更高版本中,您可以使用 type TMyContent = class(TAutoObject,IMyContent) private [Unsafe] FContainer : IMyContainer; ... end; 正如马可博客中提到的: Weak and Unsafe Interface References in Delphi 10.1 Berlin
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |