Delphi Berlin 10.1 adds [weak] references. Marco Cantu's Blog has some basics on it.
For my test I created two COM libraries holding two automation object types. The container object holds a list of the content objects while the content objects holds a weak reference to their container.
The following two scenarios were tested and worked correctly (weak references are set null and memory is released) :
- A single COM library with both interfaces and CoClasses.
- Two COM libraries one with the interfaces and another with the CoClasses
However, when I place the coclasses in two separate libraries the code produces "invalid class typecast", the error goes away when removing the [weak] attribute. Please excuse the odd sample, its purpose is simply to make the problem minimal and should not be taken as standard coding practice
Here is the first library .ridl file that defines both interfaces and the CoClass for the container:
[
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"),
dual,
oleautomation
]
interface IMyContent: IDispatch
{
[id(0x000000C9)]
HRESULT _stdcall SetWeakReferenceToContainer([in] IMyContainer* AContainer);
};
[
uuid(1F56198B-B1BE-4E11-BC78-0E6FF8E55214)
]
coclass MyContainer
{
[default] interface IMyContainer;
};
};
Here is my container implementation
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.
My second library reference the first and only contains my content interface's 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;
};
and its implementation with the weak reference
unit Unit2;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
ComObj, ActiveX, DelphiImplComLib_TLB, StdVcl, 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,
ciMultiInstance, tmApartment);
end.
I tested as follows
program Project13;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
DelphiImplComLib_TLB in 'impl\DelphiImplComLib_TLB.pas',
DelphiIntfComLib_TLB in 'Intf\DelphiIntfComLib_TLB.pas';
var
GMyContainer : IMyContainer;
GMyContent : IMyContent;
begin
GMyContainer := CoMyContainer.Create;
GMyContent := CoMyContent.Create;
GMyContainer.Add(GMyContent);
end.
Why do I get an error when I split my implementations? How can I alleviate this problem?