Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / Delphi

Smart pointers and COM-server unloading. Part 3

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
21 Nov 2015CPOL3 min read 4.8K   1  
In the article I describe an approach to handle COM-server unloading issues using smart pointers.

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:

Pascal
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 {$IFDEF DELPHIXE7_UP}System.GetTypeKind(T){$ELSE}GetTypeKind(TypeInfo(T)){$ENDIF} 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, 
    {$IFDEF DELPHIXE7_UP}
    System.GetTypeKind(T)
    {$ELSE}
    GetTypeKind(TypeInfo(T))
    {$ENDIF});
  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. 

Pascal
type
  TDummyClass = class(TObject)
  private
    FApplication: ISmartPointer<ITestUnloadApplication>;
    // Application getter.
    function GetApplication: ITestUnloadApplication;
    // Application setter.
    procedure SetApplication(
      // Application.
      const Value: ITestUnloadApplication);
  public
    // Doesn't work.
    // property Application: ITestUnloadApplication read FApplication write FApplication;
    // Works like this.
    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);
  // ITestUnloadApplication interface method called indirectly through smart pointer.
  ApplicationRef.DoSomething;
  // ITestUnloadApplication function argument is passed indirectly from smart pointer.
  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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer DIRECTUM
Russian Federation Russian Federation
I am software developer currently working at DIRECTUM company. We are developing ECM system called DIRECTUM. My core work is connected with designing, programming and debugging Delphi applications, which are the platform for our system. For database layer we are using Microsoft SQL Server.

Comments and Discussions

 
-- There are no messages in this forum --