Introduction
I will remind that in this series of articles I research cases, when COM-server application doesn't unload. In the previous part of the article we researched the reasons, which can cause application to unload and not to unload. In this part of the article I will introduce the concept of smart pointer which can become pretty useful.
Index
The article consists of several parts. Here is the full list of the article parts:
About smart pointers
The concept of smart pointers originates from the languages like C++, where programmer has deep level of control over memory allocation and deallocation procedures involved, when operations with objects are performed. As wikipedia states smart pointer is an abstract data type which simulates a pointers while providing some additional features.
Delphi language is not as flexible as C++, but with current language state it is possible to implement smart pointers with slight limitations. In my case I would like to have all references to entry-point interface registered in some global registry. Pay attention onto the fact that I talk about references to entry-point interface and not about instances of entry-point objects. We easily can extend entry-point interface object implementation but extending entry-point interface references requires some thoughts.
Good news is that there is smart pointers implementation available in Delphi.Spring4D framework. The framework source code is available on BitBucket. But currently smart pointers are not part of the main branch, so you need to find a branch, which has this implementation. There is not much code in the smart pointers implemetation so I will reproduce the code here:
type
TSmartPointer<T> = class(TInterfacedObject, ISmartPointer<T>)
private
fValue: T;
function Invoke: T; inline;
public
constructor Create; overload;
constructor Create(const value: T); overload;
destructor Destroy; override;
end;
implementation
...
constructor TSmartPointer<T>.Create;
begin
case System.GetTypeKind(T)GetTypeKind(TypeInfo(T)) of
tkClass: PObject(@fValue)^ := TActivator.CreateInstance(TypeInfo(T));
tkPointer: PPointer(@fValue)^ := AllocMem(GetTypeSize(GetTypeData(TypeInfo(T)).RefType^));
end;
end;
constructor TSmartPointer<T>.Create(const value: T);
begin
fValue := value;
end;
destructor TSmartPointer<T>.Destroy;
begin
FinalizeValue(fValue,
System.GetTypeKind(T)
GetTypeKind(TypeInfo(T))
);
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := fValue;
end;
Having such a smart pointer we can use it in many cases, when pointed type expected. We can call pointed object methods indirectly through the smart pointer. We can pass smart pointer as an argument to the function which expects pointed type. And we can even cast smart pointer to another interface, which pointed object implements. But there are some cases when transparent typecasting is not supported. In particular, we should manually create smart pointer from the pointed object and we should manually implement getter and setter methods for pointed object property, if the field has type of smart pointer.
type
TDummyClass = class(TObject)
private
FApplication: ISmartPointer<ITestUnloadApplication>;
function GetApplication: ITestUnloadApplication;
procedure SetApplication(
const Value: ITestUnloadApplication);
public
property Application: ITestUnloadApplication read GetApplication write SetApplication;
end;
...
procedure DoSomething(const ApplicationIntf: ITestUnloadApplication);
begin
...
end;
procedure TestProcedure;
var
ApplicationRef: ISmartPointer<ITestUnloadApplication>;
begin
ApplicationRef := TSmartPointer<ITestUnloadApplication>.Create(
TTestUnloadApplication.Create as ITestUnloadApplication);
ApplicationRef.DoSomething;
DoSomething(ApplicationRef);
end;
I think it is quite evident now that we can replace pointed object fields with smart pointer fields with pretty slight amount of modifications. And having references replaced we can add some additional logic into our smart pointers to keep track of interface references usage. I will produce the complete example in the next part of the article.
What's next
In this part of the article I introduced the concept of smart pointers, which we can use to extend the behavior of standard pointer variables.
In the next part of the article I will explain how to use smart pointers to keep track of application unloading cases. This part of the article will be the final one.