Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 367
  • Last Modified:

Datamodule in com object

I am relatively new to com.  I have created an activeX library with a com object.  This object creates a TStingList and I want to compare it to data retreived from SQL server and return a comma delimmeted string which contains only the matching items.

I figured that the easiest way to retrieve the data from the database is through a datamodule.  However, the create method for a datamodule requires a owner of type TComponent.  My code is basically..

interface
type
  TMyComObj = class(TTypedComObject, IMyComObj)
  private
    procedure GetStringList(var AList: TStringList);
    procedure CompareList(var AList:TStringList);
    function FormatResult(MyList: TStringList): String;
  protected
    function GetList(out AString: WideString): SYSINT; stdcall;
  end;

implementation
function MyComObj.GetList(out AString: WideString): SYSINT;
var
  MyList: TStringList;
begin
try
  MyList.Create;
  MyList := GetStringList;
  CompareList(MyList);
  AString := FormatResult(MyList);
  Result := 0;  //success
except
  On E: Exception do
  begin
    Result := 1;  //error
  end;
end;
end;

procedure MyComObj.GetStringList(var AList: TStringList);
var
  x: Integer;
begin
  for x := 1 to 10 do
  begin
    AList.Add(..AValue);
  end;
end;

procedure MyComObj.CompareList(var AList:TStringList);
var
  x: Integer;
begin
  Datamod.ADOConnection1.Open;
  Datamod.qryGetdbData.Open;
  x := 0;
  while x <= AList.Count - 1 do
  begin
    If not Locate('Field1',AList.Strings[x],[]) then
      PositionList.Delete(x);
    else
      x := x + 1;
  end;
  Datamod.qryGetdbData.Close;
  DataMod.ADOConnection1.Close;
end;

function MyComObj.FormatResult(MyList: TStringList): String;
var
  x: Integer;
begin
  for x := 0 to MyList.Count -1 do
    Result := Result + MyList.Strings[x] + ',';
end;

How can I use the datamodule inside a Com Object?  Do I need to wrap the object in a component?  Is there an easy way to do that?  Once I get it to work, I will be accessing the component from a web application using DCOM, so there is no TComponent in the calling application.

Thanks
Scott
0
ssunko
Asked:
ssunko
  • 4
  • 3
1 Solution
 
ziolkoCommented:
thats quite simple choose File -> New -> DataModule
New uunit should be generated, which will look lke this:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TDataModule1 = class(TDataModule)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DataModule1: TDataModule1;

implementation

{$R *.DFM}

end.

If You want only one instance of DataModule1 in Your COM Library add:

initialization
  DataModule1:=TDataModule1.Create(nil)
finalization
  DataModule1.Free;

then You will have access to DataModule1 in every unit where You include "Unit1" in uses clausule

before last end.

If for some reason You want mulitiple instances of TDataModule1 remove line:

var
  DataModule1: TDataModule1;

include "Unit1" in uses clausule where You need and You can use TDataModule like any other class.
You want to use DCOM? sure thing..just place TDCOMConnection on Your DataModule

ziolko.
0
 
ziolkoCommented:
should be:

.
.
.
before last end.

then You will have access to DataModule1 in every unit where You include "Unit1" in uses clausule
.
.
.
ziolko.
0
 
sfockCommented:
Hi Ziolko,

belonging to the treading Model this might be a little bit ... dangerous ;-)

Id suggest to make Datamodule1 to a Class Field like this

TMyComObj = class(TTypedComObject, IMyComObj)
 private
   FDatamodule : TDataModule1;
   procedure GetStringList(var AList: TStringList);
   procedure CompareList(var AList:TStringList);
   function FormatResult(MyList: TStringList): String;
 protected
   function GetList(out AString: WideString): SYSINT; stdcall;
  public
    property DataModule : TDataModule1 read FDatamodule;
 end;

I'd reate it in the overridden Initialize method ond destroy it in the destructor.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
ziolkoCommented:
sfock in first case (when datamodule created in initialization) one instance of datamodule will be created for each instance of COM library, I done that before nothing so far no problems in second case > If for some reason You want mulitiple instances of TDataModule1 > I meant situation You've described in your comment.
ziolko.
0
 
ssunkoAuthor Commented:
ziolko, it worked great.  Thanks for the quick response.
0
 
sfockCommented:
hi ziolko,

yes that is absolutly correct, You create one instance of the DataModule for all instances of the com object, i create an innstanbce of the DataModule for each instance of the ComObject.

If you hadn't had problems with your way then you had good luck or no high user load on your objects.
Depending of the treading Model there are multiple treads for the com object. But the DataModule is not treadsafe. so it could happen that one tread overrides data or actions of another tread like

tread1 closes query1
tread2 closes query2
tread1 sets a parameter
tread2 sets another parameter
tread1 opens the query
tread2 opens the query again

this is just an example. In this case no exception occures, but tread1 gets the results that where mentioned for tread2.

There are only two ways to avoid this:
1. Do not use global data or objects in a treaded application (like the com object is) This is the way i suggestet, or
2. Do still not use global data but global treadsafe objects --> singeltons

To go the 2nd way you'll have to build a singelton and make all his actions treadsafe. That means that you can't give out any Data (e.G a query component) out of the singelton. You have to make a kind of object proxy.

The singelton variant naturely need less memory on high user load then the "per instance" variant but it might be slower (after the treads have to way for each other) and it has the danger of tread deadlocks, so I'd not recommend it for a beginner.
But it works like this:

interface

uses
  unit2;

type
  TDataSingelton = class(TObject)
  private
    FDataMod : TDataModule2;
  public
    constructor create;
    destructor destroy; override;
    class function getInstance : TDataSingelton;
    Procedure QueryList(Name : string; ResultList : TStrings);
  end;

  function getDataSingelton : TDataSingelton; // this function is for convinience only

implementation

var
  DataSingeltonInstance : TDataSingelton;

function getDataSingelton : TDataSingelton; // this function is for convinience only
begin
  result := TDataSingelton.getInstance;
end;

{ TDataSingelton }
constructor TDataSingelton.create;
begin
  inherited create;
  FDataMod := TDataModule2.Create(nil);
end;

destructor TDataSingelton.destroy;
begin
  FDataMod.free;
  inherited;
end;

class function TDataSingelton.getInstance: TDataSingelton;
begin
  CriticalSection.aquire;
  if not assigned(DataSingeltonInstance) then
    DataSingeltonInstance := TDataSingelton.create;
  result := DataSingeltonInstance;
  CriticalSection.release;
end;

procedure TDataSingelton.QueryList(Name: string; ResultList: TStrings);
begin
  CriticalSection.aquire;
  // do the job here
  CriticalSection.release;
end;

initialization
 DataSingeltonInstance := nil;
finalization
 if assigned(DataSingeltonInstance) then
   DataSingeltonInstance.Free;

end.
0
 
ziolkoCommented:
sfock > You are absolutelly right, thats way I posted 2 versions one with global DataModule and second > "If for some reason You want mulitiple instances of TDataModule1".
ziolko.
0
 
sfockCommented:
looks like i overread one line of your comment, sorry ziolko!
But the global way is still _no good option_ ;-)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now