Link to home
Create AccountLog in
Delphi

Delphi

--

Questions

--

Followers

Top Experts

Avatar of glenn_benschop
glenn_benschop

messagebox do not display in a Thread
Hi,
I found some code about Thread (it was a link from this forum), a nice project, but the messagebox in it will not dsiplay. There are no syntax errors. When I debug the source, then the messagebox pops up., but when I run the program normally it doesn't. Also sometimes I get the error of : unknown software exception(...) occured in the application at (....), I click [OK] en then the following error occured: Exception EWin32error in Project1.exe at 00009D9c, code 1400, invalid window handle.
I'm using delphi 5 and Windows 2000 (SP4), the project has two units: it's about a project that's checking if a number is Prime or not. In both cases a message must be displayed. Can somebody help?

{****Begin First unit***************}
unit PrimeForm;

interface

uses
Ā  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Ā  StdCtrls;

type
Ā  TPrimeFrm = class(TForm)
Ā  Ā  NumEdit: TEdit;
Ā  Ā  SpawnButton: TButton;
Ā  Ā  procedure SpawnButtonClick(Sender: TObject);
Ā  private
Ā  Ā  Ā  { Private declarations }
Ā  public
Ā  Ā  Ā  { Public declarations }
Ā  end;

var
Ā  PrimeFrm: TPrimeFrm;

implementation

uses PrimeThread;

{$R *.DFM}

procedure TPrimeFrm.SpawnButtonClick(Sender: TObject);

var
Ā  NewThread: TPrimeThrd;

begin
Ā  NewThread := TPrimeThrd.Create(True);
Ā  NewThread.FreeOnTerminate := True;
Ā  try
Ā  Ā  NewThread.TestNumber := StrToInt(NumEdit.Text);
Ā  Ā  NewThread.Resume;
Ā  except on EConvertError do
Ā  Ā  begin
Ā  Ā  Ā  NewThread.Free;
Ā  Ā  Ā  ShowMessage('That is not a valid number!');
Ā  Ā  end;
Ā  end;
end;

end.
{****End of First unit**********}

{****Begin Second unit ************}
unit PrimeThread;

interface

uses
Ā  Classes;

type
Ā  TPrimeThrd = class(TThread)
Ā  private
Ā  Ā  FTestNumber: integer;
Ā  protected
Ā  Ā  function IsPrime: boolean;
Ā  Ā  procedure Execute; override;
Ā  public
Ā  Ā  property TestNumber: integer write FTestNumber;
Ā  end;

implementation

uses SysUtils, Dialogs;

function TPrimeThrd.IsPrime: boolean;

var
Ā  iter: integer;

begin
Ā  result := true;
Ā  if FTestNumber <Ā 0 then
Ā  begin
Ā  Ā  result := false;
Ā  Ā  exit;
Ā  end;
Ā  if FTestNumber <= 2 then
Ā  Ā  exit;
Ā  for iter := 2 to FTestNumber - 1 do
Ā  begin
Ā  Ā  if (FTestNumber mod iter) = 0 then
Ā  Ā  begin
Ā  Ā  Ā  result := false;
Ā  Ā  Ā  {exit;}
Ā  Ā  end;
Ā  end;
end;

procedure TPrimeThrd.Execute;
begin
Ā  if IsPrime then
Ā  Ā  ShowMessage(IntToStr(FTestNumber) + 'is prime.')
Ā  else
Ā  Ā  ShowMessage(IntToStr(FTestNumber) + 'is not prime.');
end;

end.
{****End of Second unit**********}

Zero AI Policy

We believe in human intelligence. Our moderation policy strictly prohibits the use of LLM content in our Q&A threads.


Avatar of anorganixanorganix

Hi!
You said that your project is about checking if a number is Prime or not. Here is the code (no need for PrimeThread.pas).

//////////////// begin code /////////////////

procedure TMainForm.CheckNumberButtonClick(Sender: TObject);
var
Ā  I, J: integer;
begin
Ā  if not TryStrToInt(Edit.Text,I) then
Ā  begin
Ā  Ā  MessageDlg('Please enter a valid integer value!',mtWarning,[mbOK],0);
Ā  Ā  Exit;
Ā  end;

Ā  if I<=0 then
Ā  begin
Ā  Ā  Ā MessageDlg('Please enter a positive integer value!',mtWarning,[mbOK],0);
Ā  Ā  Ā Exit;
Ā  end;

Ā  if I<=2 then
Ā  Ā  Exit;

Ā  for J:=2 to I-1 do
Ā  begin
Ā  Ā  if (I mod J)=0 then
Ā  Ā  Ā  MessageDlg(IntToStr(I)+' is not a prime number!',mtInformation,[mbOK],0)
Ā  Ā  else
Ā  Ā  Ā  MessageDlg(IntToStr(I)+' is a prime number!',mtInformation,[mbOK],0);

Ā  Ā  Break;
Ā  end;
end;

////////////////// end code ////////////////////

Hope it helps!

Ā :: Cosmin

Avatar of glenn_benschopglenn_benschop

ASKER

Well, The prime function was needed to understand how thread works. I need to undersdtand how thread works to solve another problem. This example will be expand with more code. You can consider it a course. But in order to go further with the example, I want this one to work correctly otherwise it is worthless to put more code to it. So the code is all about thread learning, and the Isprime function was needed as an example. I'm looking for futher comments.

ShowMessage is part of the VCL which is not threadsafe. Use Windows.MessageBox.

Reward 1Reward 2Reward 3Reward 4Reward 5Reward 6

EARN REWARDS FOR ASKING, ANSWERING, AND MORE.

Earn free swag for participating on the platform.


ASKER CERTIFIED SOLUTION
Avatar of gwalkeriqgwalkeriq

Link to home
membership
Log in or create a free account to see answer.
Signing up is free and takes 30 seconds. No credit card required.
Create Account

Avatar of Member_2_248744Member_2_248744šŸ‡ŗšŸ‡ø

hello glenn_benschop , , To use threads it is often nessary to know something about the windows API methods and things that the system does (and does not do) with threads. There is alot of info about threads, but you ask about why the VCL ShowMessage( Ā ) does not work in a separate thread, gwalkeriq Ā gives a link to a "thread for Delphi information web site", I looked at some of the pages there, and it seems to give much information about data access across threads (thread synconozation), but I did not see any info there about why the ShowMessage thing does not work in another thread, it is NOT because of thread sync, although that is a factor.
I will start by saying, that the windows system has threads to give processor time segments (time slice) to processes and threads, so to a windows user, it seems like that more than one thread or process is doing something at the same time, however since most computers have only one processor, there can be only one thing being done by the processor at any time. The system will switch the thread using the processor when the time alotment (time slice) for that thread ends or the request for processing from that ends (thread finishes processing or releases its processor time slice). MS says -
A multitasking operating system divides the available processor time among the processes or threads that need it. Windows is designed for preemptive multitasking; it allocates a processor time slice to each thread it executes. The currently executing thread is suspended when its time slice elapses, allowing another thread to run.
The system thread scheduler controls multitasking by determining which of the competing threads receives the next processor time slice. The length of the time slice depends on the operating system and the processor. Because each time slice is small (small for "People" time, approximately 20 milliseconds), to the user multiple threads appear to be executing at the same time.
I will not say anything about thread data syncronozation, except that I have seen several many references that all say the 32-Bit processor can NOT ever access (read, write) a memory block of Less than 32-Bits (4 Bytes), so in my thread usage, for some 32-Bit values I may not use any thread sync at all, to read or write, especially for reading, if incorrect data will not cause an exception. But there are plenty of places that say you must always sync up your thread data access.
Now for the reason that ShowMessage( ) does not work. . To properly keep track of threads and resources assigned to threads, I beleive that there is a system "list of windows created in that thread" maintained for each thread, the windows system has a window message processing (message handling and a message-queue) for each thread, that processes that thread's window messages for only the windows beloning to that thread. The ShowMessage( ) creates a pop-up window (Form) that is owned by the Application window, if you do a Showmessage( ) in a separate thread, there is no GetMessage loop (or other message handling) created for that separate thread by the Forms unit, so the ShowMessage does not work since the Application GetMessage loop is in another thread processing messages from that thread's message-queue.
Since the default message handling methods for forms are all related to the Application window, you probally should create forms ONLY in the main thread, not in any other threads.
You can create windows that work correctly in another thread, but this will require API methods of the system, not methods of the delphi Application window.

For your question, I would not create a window in that thread, even a MessageBox( ) window, since those windows would NOT make the windows of another thread (main thread) Modal. . I would use the API SendMessage( ) function, to get a form in the main thread to use ShowMessage( ) and have a Modal window.
Some code for Form2 - -



const
Ā  MsgToThread = WM_USER + 130;


type
Ā  TShowMsgThread = class(TThread)
Ā  protected
Ā  Ā  FFormHnd: THandle;
Ā  Ā  procedure Execute; override;
Ā  public
Ā  Ā  constructor Create(FormHnd: THandle);
Ā  end;


Ā  TForm2 = class(TForm)
Ā  Ā  but_ThreadSendMsg: TButton;
Ā  Ā  procedure but_ThreadSendMsgClick(Sender: TObject);
Ā  private
Ā  Ā  { Private declarations }
Ā  Ā  procedure ThreadMsg(var Msg: TMessage); message MsgToThread;
Ā  end;

var
Ā  Form2: TForm2;

implementation

{$R *.DFM}


constructor TShowMsgThread.Create(FormHnd: THandle);
begin
FreeOnTerminate := True;
inherited Create(False);
FFormHnd := FormHnd;
end;

procedure TShowMsgThread.Execute;
var
MsgRe: Integer;
begin
// MessageBox( ) shows a window, but does not make main thread windows modal
MessageBox(0,'Thread MessageBox with text display'#10'Does NOT have forms in other threads as Modal',
Ā  Ā  Ā  Ā  Ā  Ā 'Thread MessageBox', MB_ICONINFORMATION);
// I read a 32-bit Application.Handle with-out thread-sync
// even if this Application.Handle is NON-Correct Data, it does not matter since
// the SetForeGroundWindow( ) will not exception, even with bad data in Application.Handle
SetForeGroundWindow(Application.Handle);
if not IsWindow(FFormHnd) then Exit;
Sleep(2000);
// No Form windows are created in this thread
MsgRe := SendMessage(FFormHnd, MsgToThread, 37, 100);
if MsgRe <>Ā 37 then Exit;
Sleep(2000);
SendMessage(FFormHnd, MsgToThread, 37, 54321);
end;

// / / / / / / / / / / / / / / / / / / / / / / / / /


procedure TForm2.ThreadMsg(var Msg: TMessage);
begin
if Msg.WParam = 37 then
Ā  begin
Ā  Msg.Result := 37;
Ā  ShowMessage('This is message 37 from thread '+IntToStr(Msg.LParam)+#10'Forms in this thread ARE Modal');
Ā  end else
Ā  if Msg.WParam = 73 then
Ā  begin
Ā  Msg.Result := 73;
Ā  ShowMessage('73 - This is message 73 from thread '+IntToStr(Msg.LParam));
Ā  end
end;


procedure TForm2.but_ThreadSendMsgClick(Sender: TObject);
begin // button click
TShowMsgThread.Create(Handle);
end;

end;

Avatar of Member_2_248744Member_2_248744šŸ‡ŗšŸ‡ø

If you want to create a window in another thread you might try this code for form2 - -


type
Ā  TShowWndThread = class(TThread)
Ā  private
Ā  Ā  FMsg1: String;
Ā  protected
Ā  Ā  procedure Execute; override;
Ā  public
Ā  Ā  constructor Create(const Msg: String);
Ā  Ā  destructor Destroy; override;
Ā  end;


// / / / / / / / / / / / / / Ā / / /


implementation

{$R *.DFM}


const
ID_OKBut = 100;

var
aSelf: TShowWndThread;
hThreadWnd: THandle = 0;

function WndProc(hWnd,Msg,wParam,lParam:Integer):Integer; stdcall;
begin
case Msg of
Ā  WM_DESTROY: PostQuitMessage(0);
Ā  WM_COMMAND: if LOWORD(wParam) = ID_OKBUT then PostMessage(hWnd,WM_CLOSE,0,0);
Ā  end;
Result := DefWindowProc(hWnd,Msg,wParam,lParam);
end;

constructor TShowWndThread.Create(const Msg: String);
begin
FreeOnTerminate := True;
inherited Create(False);
if aSelf <>Ā nil then
Ā  Raise Exception.Create('Create Failed - There can only be one instance of TAskThread');
aSelf := Self;
FMsg1 := Msg;
end;

destructor TShowWndThread.Destroy;
begin
aSelf := nil;
inherited Destroy;
end;


procedure TShowWndThread.Execute;
var
wClass: Ā  TWndClass;
mainMsg: TMSG;
begin
ZeroMemory(@wClass, SizeOf(wClass));

with wClass do
Ā  begin
Ā  hInstance := sysInit.hInstance;
Ā  hIcon := LoadIcon(0,IDI_QUESTION);
Ā  lpfnWndProc := @WndProc;
Ā  hbrBackground := COLOR_BTNFACE+1;
Ā  lpszClassName := 'TMW Class';
Ā  hCursor := LoadCursor(0,IDC_ARROW);
Ā  end;

Windows.RegisterClass(wClass);

hThreadWnd := CreateWindowEX(0,wClass.lpszClassName,'No See',
Ā  Ā  Ā  Ā  Ā  WS_SYSMENU or WS_DLGFRAME or WS_CAPTION or WS_VISIBLE,
Ā  Ā  Ā  Ā  Ā  140,140,180,110,0,0,hInstance,nil);

CreateWindow('BUTTON', 'O K',
Ā  Ā  WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or WS_TABSTOP,
Ā  Ā  57,50,66,24,hThreadWnd,ID_OKBut,hInstance,nil);

SendMessage(CreateWindow('STATIC', PChar(FMsg1), WS_VISIBLE or WS_CHILD or SS_CENTER,
Ā  Ā  1,1,173,46,hThreadWnd,46,hInstance,nil),
Ā  Ā  WM_SETFONT,GetStockObject(ANSI_VAR_FONT),0);


// IMPORTANT
// below is the GetMessage loop for this thread, which does ONLY window message for this thread
// without it the CreateWindow( ) functions abouve are useless
// the ShowMessage( ) procedure does NOT place this in any thread
if hThreadWnd <>Ā 0 then
Ā  while GetMessage(mainMsg,0,0,0) do
Ā  Ā  if not IsDialogMessage(hThreadWnd, mainMsg) then
Ā  Ā  Ā  begin
Ā  Ā  Ā  TranslateMessage(mainMsg);
Ā  Ā  Ā  DispatchMessage(mainMsg);
Ā  Ā  Ā  end;
end;

// / / / / / / / / / / / / / / / /


procedure TForm2.but_ThreadSendMsgClick(Sender: TObject);
begin // button click
TShowMsgThread.Create(Handle);
end;

initialization

finalization
PostMessage(hThreadWnd, WM_DESTROY, 0,0);

end.

Ā = = = = = = = = = = = = = = = = = = = = = = =
maybe this give you alittle more info?

My example is taken from the link that gWalkeriq suggested( http://www.pergolesi.demon.co.uk/prog/threads/ToC.html) It is from chapter 2. Ā as I understand from this link and the comments of Slick812, the VCL is not threadsafe, so the eaxample from the link is wrong. They went futher in Ā chapter 3 and they use a memo instead of a messagebox to display the result of Prime function and that works (I tried it myself), because then they use the function Synchronize. So, if I want to, let say repaint my form, I have to call synchronize. What do I have to do with the points, I don't feel like the comments solved the problem, although the statements in the comments were true, so I 'll keep the points. But, many thanks for all your efforts and Ā comments to my question.

Here is the working code of the second unit (with a memo and the Synchornize function.

unit PrimeThread;

interface

uses
Ā  Classes;

type
Ā  TPrimeThrd = class(TThread)
Ā  private
Ā  Ā  FTestNumber: integer;
Ā  Ā  FResultString: string;
Ā  protected
Ā  Ā  function IsPrime: boolean;
Ā  Ā  Ā procedure UpdateResults;
Ā  Ā  procedure Execute; override;
Ā  public
Ā  Ā  property TestNumber: integer write FTestNumber;
Ā  end;

implementation

uses SysUtils, Dialogs, PrimeForm;

function TPrimeThrd.IsPrime: boolean;

var
Ā  iter: integer;

begin
Ā  result := true;
Ā  if FTestNumber <Ā 0 then
Ā  begin
Ā  Ā  result := false;
Ā  Ā  exit;
Ā  end;
Ā  if FTestNumber <= 2 then
Ā  Ā  exit;
Ā  for iter := 2 to FTestNumber - 1 do
Ā  begin
Ā  Ā  if (FTestNumber mod iter) = 0 then
Ā  Ā  begin
Ā  Ā  Ā  result := false;
Ā  Ā  Ā  {exit;}
Ā  Ā  end;
Ā  end;
end;

procedure TPrimeThrd.UpdateResults;
begin
Ā  PrimeFrm.ResultsMemo.Lines.Add(FResultString);
Ā  showmessage(FResultString); Ā //also works


end;

procedure TPrimeThrd.Execute;
begin
Ā  if IsPrime then
Ā  Ā  Ā  FResultString := IntToStr(FTestNumber) + ' is prime.'
Ā  else
Ā  Ā  FResultString := IntToStr(FTestNumber) + ' is not prime.';
Ā  Ā  Ā Synchronize(UpdateResults);

Ā  {
Ā  if IsPrime then
Ā  Ā  ShowMessage(IntToStr(FTestNumber) + 'is prime.')
Ā  else
Ā  Ā  ShowMessage(IntToStr(FTestNumber) + 'is not prime.');
Ā  Ā }
end;

end.


Free T-shirt

Get a FREE t-shirt when you ask your first question.

We believe in human intelligence. Our moderation policy strictly prohibits the use of LLM content in our Q&A threads.


Avatar of Member_2_248744Member_2_248744šŸ‡ŗšŸ‡ø

I read your last comment above, but I did not understand what you were talking about. I tried to get what you may be refering to in your comment, but I think I may be "Mixing Up" tech terms. Your question here was about why the ShowMessage did not work in a separate thread, I tried to give you some info about that. But it may be that we are not talking about the same thing, to me there is a difference between a method (Showmessage) "working" in a thread and being "called" from a thread. My comments (and Ā maybe others) were for runnning that code in the TTHread , not calling that code from the thread. In your comment code above you use the
Ā  Ā  Synchronize(UpdateResults);
that adds to the Memo and uses ShowMessage( ), I seemed to get from your comment that you think that the memo addition and ShowMessage are executed in that Thread, This is NOT the case - - they are executed in the main thread, because you call the Ā -
Synchronize( ) method, it is true that you "call" these methods (ShowMessage) in the code for your TThread, but they are "working" (processor time slice) in the main thread, not in your thread's time slice. I even looked at the explanation in the web site you gave for chapter three, and I think he says this about Syncronize, and even has a chart that shows you that the TThread is suspended and the main thread is allowed to run the code in the Syncronize( ) method.

here is the code I have in Classes.pas for the TThread.Synchronize -


procedure TThread.Synchronize(Method: TThreadMethod);
begin
FSynchronizeException := nil;
FMethod := Method;
SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
// please notice that this uses the thread-safe and thread-efficient API SendMessage( )
// which runs the code in the FMethod in the main thread, not in this thread
if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;

I guess I did not understand what you were asking?
The Ā Synchronize( ) Ā  TThread method is what you use to run code in the main thread, it has this in the Delphi help, it says -

Ā "Executes a method call within the main VCL thread "Ā but I did not think your question was about that.


Slick812 and ohters,
I should be also more specific, I apologize for that. Next time I'll be more precisely.

Avatar of Member_2_248744Member_2_248744šŸ‡ŗšŸ‡ø

By the way, using Ā Synchronize( ) is thread safe , , ,
I will guess that you may not get any more posts here, Ā you may should finalize this question. . . .
as to your points question -
since gwalkeriq Ā gave you the link to the Info that you used to develop the code that worked (display the ShowMessage, this a correct way to do that), here at EE it seems the usual is that you might should award him the points. . . ?

Reward 1Reward 2Reward 3Reward 4Reward 5Reward 6

EARN REWARDS FOR ASKING, ANSWERING, AND MORE.

Earn free swag for participating on the platform.


Slick812,
You're right about the points, I will give those to gwalkeriq.
Delphi

Delphi

--

Questions

--

Followers

Top Experts

Delphi is the most powerful Object Pascal IDE and component library for cross-platform Native App Development with flexible Cloud services and broad IoT connectivity. It provides powerful VCL controls for Windows 10 and enables FMX development for Windows, Mac and Mobile. Delphi is your choice for ultrafast Enterprise Strong Developmentā„¢. Look for increased memory for large projects, extended multi-monitor support, improved Object Inspector and much more. Delphi is 5x faster for development and deployment across multiple desktop, mobile, cloud and database platforms including 32-bit and 64-bit Windows 10.