We help IT Professionals succeed at work.

Using BeginThread and calling procedure from withing the thread

moonrise
moonrise asked
on
2,301 Views
Last Modified: 2007-12-19

I use BeginThread (this thread just waits for data coming from a swipe reader)

      vUSBReaderThreadHandle := BeginThread(nil, 0, @ReadUSBCard, 0, 0, vUSBReaderThreadID);

Then withing the ReadUSBCard, I need to call a procedure FormMain.processCardInfo(cardinfo)

1 - Is it safe to do that (only one instance of that thread exists)

2 - cardinfo is a variable within ReadUSBCard but I can't seem to be able to use it as a parameter for  FormMain.processCardInfo(cardinfo)

3 - My application does not seem to close completely since I have added that thread - there is a while true loop in the thread - how do I kill it when the program is closed

Thank you
Comment
Watch Question

Software Engineer, Advisory
CERTIFIED EXPERT
Top Expert 2005
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION

Commented:
Try this out...




unit Unit1;

interface

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


  Type TCardInfo = record
        YourData:Integer;
        YourOtherData:String;
        end;

  type TCardReaderThread = class(TThread)
  private
    FCardInfo:TCardInfo;
    procedure DoProcessCardInfo;
  public
    constructor Create(PossibleOptions:Integer);
  protected
    procedure Execute; override;
  end;

type
  TForm1 = class(TForm)
  private
    procedure ProcessCardInfo(CardInfo: TCardInfo);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ProcessCardInfo(CardInfo:TCardInfo);
begin
  // Do your processing here
end;

{ TCardReaderThread }

constructor TCardReaderThread.Create(PossibleOptions: Integer);
begin
  inherited create(True);
  FreeOnTerminate := True;
  Resume;
end;

procedure TCardReaderThread.Execute;
begin
  inherited;

  //Read Card Info Here
  //FCardInfo := Whatever
  synchronize(DoProcessCardInfo);
  Terminate;
end;

procedure TCardReaderThread.DoProcessCardInfo;
begin
  Form1.ProcessCardInfo(FCardInfo);
end;

end.

Author

Commented:
Thank you Russel, works great.

Author

Commented:
Hi, I just realized a problem - here is my scenario

I have a form called FormMainMenu where the thread is, etc...  and FForm is that form.

The following procedure is my DoCallBack

procedure TCardReader.DoCallback;
begin
  // Running in main thread now... can access the vcl safely
  if Assigned(FForm) then
  begin
     FForm.ProcessCardInfo(FCardInfo);
  end;
end;

ProcessCardInfo is invoked fine, and as part of it an other form is displayed FormPayment (from within ProcessCardInfo) - then here is the problem:

FormPayment calls a procedure  FormMainMenu.ProcessPayment - this causes an access violation

Any idea?

Thank you


Russell LibbySoftware Engineer, Advisory
CERTIFIED EXPERT
Top Expert 2005

Commented:
Would it be possible to the see code from the ProcessCardInfo and ProcessPayment routines? Might make it a little easier to debug.

Thanks,
Russell

Author

Commented:
Hi, hopefully this will help

First here is part of my execute procedure - I tried to only leave what I think might matter

procedure TCardReader.Execute;
begin
    while (not Terminated) do
    begin
     // This line waits until a card is swiped
      vResult := TheDevUSBReader.ReadFile(vUSBReaderBufferRead, TheDevUSBReader.Caps.InputReportByteLength, vRead);
      if (vResult) then
      begin
          .....   we get info read from card ...
          fCardInfo := String(Tk1Data) + String(Tk2Data);

          // Callback
          Synchronize(DoCallback);
     end;
end;

procedure TCardReader.DoCallback;
begin
  // Running in main thread now... can access the vcl safely
  if Assigned(FForm) then
  begin
     // Do the callback
     FForm.ProcessCardInfo(FCardInfo);
  end;
end;


procedure TFormMainMenu.ProcessCardInfo(pCardInfo: String);
begin
//stuff here....
            with TFormPurchase.Create(Self) do
            begin
              // set some value here for the form newly created
              Show;
            end;
//stuff here....
end;

At this point the user is looking at the new form  from TFormPurchase.Create(Self)
On that form he clicks on a button that triggers the following code

procedure TFormPurchase.ButtonAcceptClick(Sender: TObject);
begin
      FormMainMenu.ProcessPayment( ....  a bunch of private properties passed here ...);
     Close;
 end;

end;


Russell LibbySoftware Engineer, Advisory
CERTIFIED EXPERT
Top Expert 2005

Commented:

I took the original code i posted to you, added a second form which gets created  via:

procedure TForm1.ProcessCardInfo(CardInfo: String);
begin

  // Psuedo code example
  Caption:=CardInfo;
  with TForm2.Create(Self) do
  begin
     Caption:=CardInfo;
     Show;
  end;

end;

Then in form2, if the button is clicked:

procedure TForm2.Button1Click(Sender: TObject);
begin

  Form1.ProcessPayment('Testing');
  Close;
 
end;

Form1's ProcessPayment then displays a message:

procedure TForm1.ProcessPayment(PaymentInfo: String);
begin

  ShowMessage('Called from form2');
 
end;

I let it create multiple forms, and then clicked the buttons to force the callback into form1, all without any sort of problems.

I guess for starters it would be good to know the exception Type and address. Also, are you attempting to access any of the thread properties at any point during this processing? Any passing of variables as "var" (by reference). Just checking for things that may cause a problem....

Another suggestion as well:
Have you tried "dummying" the code so that the thread is not created, but you have a test procedure that you use to call ProcessCardInfo, just so you can test the flow of things.

One of those things where it MAY be related to thead, and then again, maybe not.

Hope this helps, let me know if I can assist further,
Russell


Author

Commented:
Thank you for all this work. Now that I know I'm not doing something obviously wrong or illegal I will do as you say.

Author

Commented:
I changed a global variable for a private property for the form and it seems to have fixed the problem. Thank you again.
Russell LibbySoftware Engineer, Advisory
CERTIFIED EXPERT
Top Expert 2005

Commented:

You are very welcome, glad to hear you got it sorted out.

Russell
Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.