13

I have a problem. I have a VCL application using a thread. This thread does some calculations and calls a MainForm's method through Synchronize(). It all works just fine, I have a "Start" button, which creates and runs the thread and a "Stop" button which stops and frees it. No errors, no nothing.

But for some reason when I close the application and I've run the thread I get a EOSError 1400 - Invalid window handle. I've breakpointed the OnClose procedure and the only thing I do there is saving an ini file, no error in that, when I trace further (using F7), I get to the very end (Application.Run; end.), after "calling" the end. I get the error, so there is no specific line of code raising it.

I hope the question is somewhat clear and I hope it's solvable, because just ignoring the error seems a bit unclean.

Thanks inb4


ANSWER

This error occured to me when the Execute method of a thread was called, it looked like this:

procedure TRunThread.Execute;
var (...)
begin
  while not Terminated do begin
    (...)
    MainForm.Memo1.Lines.Add('Some text'); // Even though this call worked fine during
    //the application running, it caused errors on shutting the app down.
    // For acccessing GUI elements, it's necessary to use Synchronize()
    (...)
  end;
end;
Martin Melka
  • 7,177
  • 16
  • 79
  • 138
  • 1
    Are you sure your thread is not running anymore at this point ("at the very end of Application.run")? – gabr Jun 15 '11 at 06:33
  • I am. Whether I close the application while the thread is running or not, I get this error. _Yeah, and for what did I deserve the "-1"? I tried to describe my problem as well as I could._ – Martin Melka Jun 15 '11 at 06:39
  • 4
    Why downvote? This is a kind and valid question. I voted this up to make up for the downvote. These unjustified downvotes seem to be getting out of control recently :-/ – jpfollenius Jun 15 '11 at 06:42
  • Please show relevant source code – Lars Truijens Jun 15 '11 at 06:42
  • @Lars okay, I will try to dig some relevant pieces. – Martin Melka Jun 15 '11 at 06:44
  • @Lieven Seems I failed at English this time. I mean _"when I **had** run the thread at least once"_, i.e. the thread was started at some point of the application running and if it's running or not at the end doesnt matter. – Martin Melka Jun 15 '11 at 06:50
  • You have added innocent code that does not explain anything. – kludg Jun 15 '11 at 07:15
  • @Serg yeah, the thing is I don't really know what to post. I will try to update it again. – Martin Melka Jun 15 '11 at 07:52
  • It's kinda normal to place the inherited create call at the start of the thread constructor, (with 'true'), and resume the thread at the end, but in recent Delphi versions, this no longer seems to matter much, not sure why... Anyway, just as a test, what happens if you place an 'exit' call as the first line of your execute method, ie you do not run the bulk of your method? – Martin James Jun 15 '11 at 07:59
  • 1
    It was probably downvoted because the original question could not be answered. It still can't be answered even with the addition of some code. If questions are unclear they should be downvoted, that's how the site works as I understand it. – David Heffernan Jun 15 '11 at 08:47
  • @Serg Well, not innocent at all. @Magicmaster Calling Free just after Terminate is asking for trouble. Use WaitFor in between. – NGLN Jun 15 '11 at 08:58
  • @NLGN - No, that is correct. `TThread.Destroy` calls `WaitFor` internally. BTW it calls `Terminate` also, so no need for a separate `TRunThread.Terminate` call. – kludg Jun 15 '11 at 09:07
  • @Serg Ok, thanks for clearing that up. – NGLN Jun 15 '11 at 09:10
  • 3
    @David: I agree but if the OP does his best to describe the situation it would be better IMHO to request more information from him. And besides, a downvote without a comment is NEVER helpful. – jpfollenius Jun 15 '11 at 09:13
  • Please show the TThread.Execute code – Lars Truijens Jun 15 '11 at 10:12
  • @David I would be more than glad to provide the necessarry info, but I have no idea which part of it causes the problems, so I asked generally like this to gain some point of view, if you understand me. If I posted that 500~ lines long source straightaway, people would flame me too :) Nevermind that, I will try to update the question with more code... – Martin Melka Jun 15 '11 at 10:12
  • Which window handle is invalid? – David Heffernan Jun 15 '11 at 10:18
  • 1
    Omigosh. Pardon all this fuss, while formatting the `.Execute` method to post, I noticed there is one direct(unsynced) call of `MainForm.Memo1.Lines.Add();` . For some reason I put it on a same line as another command. Damn me. Sorry and thank you. After commenting it out, no more errors appear. – Martin Melka Jun 15 '11 at 10:24
  • IMO, the question should be re-written as a post-mortem, describing the problem, the errant call to Memo1.Lines.Add, and a statement along the lines of "you can expect EOSError 1400 if you do this in a thread". Otherwise, the downvotes will continue. – Chris Thornton Jun 15 '11 at 13:21
  • -1 reversed to +1, thanks for making the question more valuable. – Chris Thornton Jun 15 '11 at 15:41

2 Answers2

12

A possible reason is some unsynchronized access to GUI from the thread. You said that the thread does not do it, but without seeing the TRunThread.Execute source code that looks like the best guess.

kludg
  • 27,213
  • 5
  • 67
  • 118
1

I had the same problem, error code 5 Access is denied. This turned out to related to a thread started to test an internet connection on an embedded panel (using BeginThread). If the user exits the form (which is testing the internet connection) immediately after displaying the form, the AV occurs.

On my development PC, the internet connection test was successful...and so fast I never saw the problem! After struggling for several hours, I finally tracked it down to this thread and reproduced it by disconnecting my network cable.

The solution was straightforward: When exiting the form (eg. in the FormDestroy event) ensure the thread is definitely not running before continuing.

AlainD
  • 5,413
  • 6
  • 45
  • 99