?
Solved

Datamodule in com object

Posted on 2003-03-11
8
Medium Priority
?
363 Views
Last Modified: 2013-11-23
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
Comment
Question by:ssunko
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
8 Comments
 
LVL 21

Accepted Solution

by:
ziolko earned 2000 total points
ID: 8113110
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
 
LVL 21

Expert Comment

by:ziolko
ID: 8113137
should be:

.
.
.
before last end.

then You will have access to DataModule1 in every unit where You include "Unit1" in uses clausule
.
.
.
ziolko.
0
 
LVL 3

Expert Comment

by:sfock
ID: 8113796
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 21

Expert Comment

by:ziolko
ID: 8113987
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
 

Author Comment

by:ssunko
ID: 8114421
ziolko, it worked great.  Thanks for the quick response.
0
 
LVL 3

Expert Comment

by:sfock
ID: 8114446
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
 
LVL 21

Expert Comment

by:ziolko
ID: 8115276
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
 
LVL 3

Expert Comment

by:sfock
ID: 8117423
looks like i overread one line of your comment, sorry ziolko!
But the global way is still _no good option_ ;-)
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question