Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Thread not executing in ActiveX form - but does elsewhere 2

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I have a thread, called TAlertThread. The thread interacts with its owner by triggering events. For example, when certain data is available inside the thread, it sets some temp variables and calls Synchronize(UpdateAlert) which in turn triggers the appropriate event.

Now the thread works perfectly in any standard windows application. My problem is when I put that thread inside of an ActiveX form (TActiveForm). The ActiveX control (aka COM object) is then embedded inside of a Windows Desktop Gadget (via HTML / Javascript). I also have experience with this, the gadget is not the issue. The ActiveX component works fine in its destination, except the thread is never executed. It's even being called EXACTLY the same way as I called it from the App.

Is this some limitation with ActiveX, blocking threads from executing? I wouldn't think so, because other things that require threads internally (such as TADOConnection) work. I am in fact properly calling CoInitialize and CoUninitialize appropriately. Again, works perfect in an application, but does not work at all in ActiveX.

JD Solutions
 
Here is how I call this thread...

Code:
procedure TRMPDashXS.ExecThread;
begin
  //Thread created suspended
  lblStatus.Caption:= 'Executing Thread...'; 
  fThread:= TAlertThread.Create(fConnStr); //fConnStr = connection string
  fThread.Priority:=      tpIdle;
  fThread.OnConnect:=     Self.ThreadConnected;
  fThread.OnDisconnect:=  Self.ThreadDisconnected;
  fThread.OnBegin:=       Self.ThreadStarted;
  fThread.OnFinish:=      Self.ThreadFinished;
  fThread.OnAlert:=       Self.ThreadAlert;
  fThread.OnAmount:=      Self.ThreadAmount;
  fThread.Resume; //Execute the thread
end;

JD Solutions
 
Actually here's the entire thread, in exception of the last procedure which is too large to fit and isn't related to the problem...

Code:
unit AlertThread;

interface

uses
  Windows, Messages, SysUtils, Classes, Registry, DB, ADODB,
  ComObj, ActiveX, ComCtrls, DateUtils, StdCtrls, Controls, Dialogs;

type          
  TAlertEventType = (aeConnect, aeDisconnect, aeStart, aeFinish);
  TAlertType = (atSalesMonthLast, atSalesMonthYear, atSalesQuarter, atSalesYear, atOverdueApprovals,
    atUnlinkedBO, atPODueToday, atOverduePO, atPurchConsign, atPickupDelivery);
  TAmountType = (amToday, amYesterday, amTodayLastWeek, amTodayLastMonth, amTodayLastYear,
    amThisWeek, amLastWeek, amThisMonth, amLastMonth, amThisMonthLastYear, amThisYear, amLastYear);
  TAccountBO = (abInvoiceCreated, abItemSold);
          
  TAlertEvent = procedure(Sender: TObject; const T: TAlertType; const S: String; const ID: Integer) of object;
  TAmountEvent = procedure(Sender: TObject; const T: TAmountType; const Amount: Currency) of object;

  TAlertThread = class(TThread)
  private     
    fStep: Integer;
    fConnStr: String;
    fDataReady: Bool;
    fVal: string;
    fInd: Integer;
    fTyp: TAlertType;
    cst, cst2, cst3: Currency;
    C_Date: TDate;
    C_DateTime: TDateTime; 
    fEventType: TAlertEventType;
    fDB: TADOConnection;
    Q: TADODataset;
    fOnFinish: TNotifyEvent;
    fOnBegin: TNotifyEvent;
    fOnDisconnect: TNotifyEvent;
    fOnConnect: TNotifyEvent;
    fOnAlert: TAlertEvent;
    fOnAmount: TAmountEvent;
    procedure ThreadTerminated(Sender: TObject);
    procedure DBConnect(Sender: TObject);
    procedure DBDisconnect(Sender: TObject);
    procedure DoEvent;
    procedure DoAlerts;
    function ConnectDB: Bool; 
    procedure UpdateAlert;
    procedure DoStep;
  protected
    procedure Execute; override;
  public       
    ConsThreshold, CommTimeout: Integer;
    cryr:   string;
    pryr:   string;
    pryr1:  string;
    pryr2:  string;
    pryr3:  string;
    yr1, yr2, yr3, yr4, yr5: string;
    monthC, yearC: currency;
    constructor Create(const AConnStr: String);
  published
    property OnBegin: TNotifyEvent read fOnBegin write fOnBegin;
    property OnFinish: TNotifyEvent read fOnFinish write fOnFinish;
    property OnConnect: TNotifyEvent read fOnConnect write fOnConnect;
    property OnDisconnect: TNotifyEvent read fOnDisconnect write fOnDisconnect;
    property OnAlert: TAlertEvent read fOnAlert write fOnAlert;
    property OnAmount: TAmountEvent read fOnAmount write fOnAmount;
  end;

implementation

{ TAlertThread }

function TAlertThread.ConnectDB: Bool;
begin
  Result:= False;
  if fDB.Connected then Exit;
  fDB.ConnectionString:= fConnStr;
  try
    fDB.Connected:= True;
    Result:= True;
  except
  end;
end;

constructor TAlertThread.Create(const AConnStr: String);
begin                     
  FreeOnTerminate:= True;
  inherited Create(True);
  OnTerminate:= ThreadTerminated;
  fConnStr:= AConnStr;
  CoInitialize(nil);
  try
    fDB:= TADOConnection.Create(nil);
      fDB.LoginPrompt:= False;
      fDB.ConnectionString:= fConnStr;
      fDB.AfterConnect:= Self.DBConnect;
      fDB.AfterDisconnect:= Self.DBDisconnect;
    Q:= TADODataSet.Create(nil);
      Q.Connection:= fDB;
             
  finally
    CoUninitialize;
  end;
end;

procedure TAlertThread.DBConnect(Sender: TObject);
begin
  if assigned(fOnConnect) then fOnConnect(Self);
end;

procedure TAlertThread.DBDisconnect(Sender: TObject);
begin
  if assigned(fOnDisconnect) then fOnDisconnect(Self);
end;
    
procedure TAlertThread.DoEvent;
begin
  case fEventType of
    aeConnect: begin
      if assigned(fOnConnect) then fOnConnect(Self);
    end;
    aeDisconnect: begin
      if assigned(fOnDisconnect) then fOnDisconnect(Self);
    end;
    aeStart: begin
      if assigned(fOnBegin) then fOnBegin(Self);
    end;
    aeFinish: begin
      if assigned(fOnFinish) then fOnFinish(Self);
    end;
  end;
end;

procedure TAlertThread.DoStep;
begin
  if assigned(fOnAlert) then
    Self.fOnAlert(Self, fTyp, fVal, fInd);
end;

procedure TAlertThread.Execute;
begin
  if Terminated then Exit;
  fEventType:= aeStart;
  Synchronize(DoEvent);
  try
    CoInitialize(nil);
    try
      if ConnectDB then begin
      
        //CODE GOES HERE
        DoAlerts;

      end;
    finally
      CoUninitialize;
    end;
  finally
    fEventType:= aeFinish;
    Synchronize(DoEvent);
  end;
end;

procedure TAlertThread.ThreadTerminated(Sender: TObject);
begin
  if assigned(Q) then begin
    Q.Close;
    Q.Free;
    Q:= nil;
  end;
  if assigned(fDB) then begin
    fDB.Connected:= False;
    fDB.Free;
    fDB:= nil;
  end;
end;

procedure TAlertThread.UpdateAlert;
begin
  if assigned(fOnAlert) then begin
    Self.fOnAlert(Self, fTyp, fVal, fInd);
  end;
end;

procedure TAlertThread.DoAlerts;
begin
  //PROCEDURE TRUNCATED BECAUSE IT IS VERY LARGE - problem for sure does not come from here
end;

end.


JD Solutions
 
Jerry, what delphi version are you using?

I must verify this in XE, never encountered this problem.
But it is interesting indeed.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
I'm using Delphi7. Haven't tried it in any other version.

JD Solutions
 
mmm,
looking at the delphi XE code, this is still the case.
CheckSynchronize needs to be called from the moment you are doing threading in a DLL.

Will put this in the Big Book Of Tricks...

Thanks,
Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top