3

'MyThread' does not run. I do not know whether the problem happens on 'DataTransferServiceStart' procedure. I guess the 'DataTransferServiceStart' procedure does not execute. IDE is Delphi XE. Please help me, thank you very much.

Thread's Unit:

unit Unit_MyThread;

interface

uses
  Classes, SysUtils;

type
  TMyThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation


procedure TMyThread.Execute;
var
  log: TextFile;
  logPath: String;
  i: Integer;
begin
  logPath := 'd:\test.log';
  AssignFile(log, logPath);
  Append(log);
  i := 0;
  while not self.Terminated do
  begin
    Sleep(1);
    Writeln(log, IntToStr(i));
    if i=10 then
      Terminate;
    i := i + 1;
  end;
  CloseFile(log);
end;

end.

Main Service Unit:

unit Unit_main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  ExtCtrls, DB, ADODB, Unit_MyThread;

type
  TDataTransferService = class(TService)
  DBSrc: TADOConnection;

  procedure DataTransferServiceStart(Sender: TService; var Started: Boolean);
  procedure DataTransferServiceContinue(Sender: TService; var Continued: Boolean);
  procedure DataTransferServicePause(Sender: TService; var Paused: Boolean);
  procedure DataTransferServiceStop(Sender: TService; var Stopped: Boolean);

  public
    function GetServiceController: TServiceController; override;
  end;
var
  DataTransferService: TDataTransferService;
  MyThread: TMyThread;
implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  DataTransferService.Controller(CtrlCode);
end;

function TDataTransferService.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TDataTransferService.DataTransferServiceStart(Sender: TService;
  var Started: Boolean);
begin
  MyThread := TMyThread.Create(False);
  Started := True;
end;

procedure TDataTransferService.DataTransferServiceContinue(Sender: TService;
  var Continued: Boolean);
begin
  MyThread.Start;
  Continued := True;
end;

procedure TDataTransferService.DataTransferServicePause(Sender: TService;
  var Paused: Boolean);
begin
  MyThread.Suspended := true;
  Paused := True;
end;

procedure TDataTransferService.DataTransferServiceStop(Sender: TService;
  var Stopped: Boolean);
begin
  MyThread.Terminate;
  Stopped := True;
end;

end.
LU RD
  • 34,438
  • 5
  • 88
  • 296
Rei Yau
  • 43
  • 1
  • 5
  • 2
    Where does it fail. How does it fail. – David Heffernan Sep 17 '12 at 23:11
  • 2
    Does 'd:\test.log' already exist? – Martin James Sep 17 '12 at 23:22
  • 4
    What does "does not work" mean *specifically*? If you want help, you need to provide the information we can use to try and provide it to you. "does not work" is meaningless without explaining what you mean. – Ken White Sep 17 '12 at 23:30
  • Please, try to formulate your question in specific and informative way. Good guidelines for example are http://www.catb.org/esr/faqs/smart-questions.html Bonus: when you follow such guidelines you made yourself better udnerstadnd the problem and sometimes find the solution yourself, "yellow duckling" principle. – Arioch 'The Sep 18 '12 at 07:06
  • @David The thread looks like not running. I do not find the problem. – Rei Yau Sep 18 '12 at 07:16
  • @KenWhite, 'd:\test.log' does exist. – Rei Yau Sep 18 '12 at 07:20
  • What makes you think thread does not run? What debugging have you performed? – David Heffernan Sep 18 '12 at 07:22
  • SysInternals Proccess Monitor would show you if you program tried/could open the thread and tried/could write into it – Arioch 'The Sep 18 '12 at 07:39

1 Answers1

2

Your service is most likely failing to start because you have a TADOConnection component dropped into your service. You cannot do this in services. Since ADO is COM, you must initialize each thread with CoInitialize(nil) and CoUninitialize, and only create/use your database components within this.

uses
  ActiveX;

procedure TDataTransferService.DataTransferServiceStart(Sender: TService;
  var Started: Boolean);
begin
  CoInitialize(nil);
  DBSrc:= TADOConnection.Create(nil);
  //Initialize and Connect DBSrc
  MyThread := TMyThread.Create(False);
  Started := True;
end;

procedure TDataTransferService.DataTransferServiceStop(Sender: TService;
  var Stopped: Boolean);
begin
  MyThread.Terminate;
  //Disconnect DBSrc
  DBSrc.Free;
  CoUninitialize;
  Stopped := True;
end;

Read here: Ok to use TADOConnection in threads

Community
  • 1
  • 1
Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • You have an extra `CoUnitialize` in your code. You're calling `CoInitialize` once in `DataTransferServiceStart`, but calling `CoUnitialize` in both `DataTransferServiceStop` and in the `finally` block in `Execute`. – Ken White Sep 18 '12 at 12:49
  • Whoops, I meant to delete that first block. I was in a hurry to go when I posted that. – Jerry Dodge Sep 18 '12 at 13:08
  • Hmm.. I noticed the 'DBSrc: TADOConnection', but ignored it since it did not seem to be created anywhere. – Martin James Sep 18 '12 at 16:32
  • Well if it's before the `private` section (which in there case there isn't even a private section), that means it's embedded right into the service, meaning it's auto-created when the app is initialized – Jerry Dodge Sep 18 '12 at 17:14
  • @ReiYau, your best bet is to encapsulate ALL your code inside the thread, including your database. You do still need to worry about `CoInitialize(nil)` because it's within a thread; just don't put it in your service's main thread. It is technically possible, but always discouraged to put code directly in the service - it's common practice to enclose all your code inside a thread, and run that thread when the service starts. – Jerry Dodge Sep 18 '12 at 17:19