Delphi OOP timer message - delphi

Finding the timer thread is the issue. I have a parent object with a timer message copied out of TCustomGrid.
private
procedure WMTimer(var Msg: TWMTimer); message WM_TIMER; .....................................
Its parent is TWinControl. It calls TimerEvent(ID: Integer); virtual; in the protected part of my object. I override this in my descendant object and the procedure first contains Inherited; in it. I use a SetTimer(Handle, 1, 60, nil); in my create and in the procedure TimerEvent last uses KillTimer(Handle, 1); at the bottom. WMTimer fitted with a breakpoint, but will not stop the timer thread anywhere in my code. Also TimerEvent(ID: Integer); has a break point with same result everywhere. I have no problems with the object's handle as I'm using it for other things with no problems. Am I missing something like some hit call.

Finding the timer thread is the issue.
Timers do not create threads. The timer messages and callbacks are executed on the thread that called SetTimer.
Whatever your problem is, it's not related to the existence of a timer thread. If you want further help with the problem I suggest you post a new question with an MCVE.
At a wild guess, you could very well be subject to VCL window re-creation. The window handle that you pass when you create the timer has destroyed and re-created during the lifetime of the VCL control. This is very normal behaviour.
You should not use a VCL control's window handle in this way since the window is subject to re-creation. Instead use a bespoke window handle created with a call to AllocateHWnd. The point about windows created with AllocateHWnd is that you are in control of their lifetime.

Related

OnShown event for TForm?

At program start, in the OnActivate event handler, I need to do something which blocks the program for a few seconds. During this time the form's client area is still not completely painted, which looks ugly for the user. (During this blocked time I don't need the program to respond to clicks or other user actions, so there is no need to put the blocking operation into a thread - I just need the form to be completely painted). So I use TForm.Update and Application-ProcessMessages to update the form before the blocking operation which works very well:
procedure TForm1.FormActivate(Sender: TObject);
begin
Form1.Update;
Application.ProcessMessages;
Sleep(7000);
end;
However, I wonder whether there is not another more elegant solution for this problem. This could be for example a OnShown event implemented in a descendant of TForm which will be fired AFTER the form has been completely painted. How could such an event be implemented?
Your real problem is that you are blocking the UI thread. Simply put, you must never do that. Move the long running task onto a different thread and thus allow the UI to remain responsive.
If you are looking for event which is fired when application finishes loading/repainting you should use TApplication.OnIdle event
http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Forms.TApplication.OnIdle
This event is fired once application is read to recieve users input. NOTE this event will be fired every time application becomes idle so you need to implement some controll variable which will tel you when OnIdle even was fired for the first time.
But as David already pointed out it is not good to block your UI (main thread). Why? When you block your main thread the application can't normally process its messages. This could lead to OS recognizing your application as being "Hanged". And aou definitly wanna avoid this becouse it could cause the users to go and forcefully kill your application whihc would probably lead to data loss. Also if you ever wanna design your application for any other platforms than Windows your application might fail the certification proces becouse of that.
In the past a simple PostMessage did the trick.
Essentially you fire it during DoShow of the base form:
procedure TBaseForm.DoShow;
begin
inherited;
PostMessage(Handle, APP_AFTERSHOW, 0, 0);
end;
then catch the msg and create an AfterShow event for all forms inherited from this base form.
But that no longer works, well not if you are skinning and have a good number of VCL controls.
My next trick was to spawn a simple thread in DoShow and check for IsWindowVisible(Handle) and IsWindowEnabled(Handle). That really sped things up it cut 250ms from load time since db opening and other stuff was already in the AfterShow event.
Then finally I thought of madHooks, easy enough to hook the API ShowWindow for my application and fire APP_AFTERSHOW from that.
function ShowWindowCB(hWnd: HWND; nCmdShow: Integer): BOOL; stdcall;
begin
Result := ShowWindowNext(hWnd, nCmdShow);
PostMessage(hWnd, APP_AFTERSHOW, 0, 0);
end;
procedure TBaseForm.Loaded;
begin
inherited;
if not Assigned(Application.MainForm) then // Must be Mainform it gets assigned after creation completes
HookAPI(user32, 'ShowWindow', #ShowWindowCB, #ShowWindowNext);
end;
To get the whole thing to completely paint before AfterShow it still needed a ProcessPaintMessages call
procedure TBaseForm.APPAFTERSHOW(var AMessage: TMessage);
begin
ProcessPaintMessages;
AfterShow;
end;
procedure ProcessPaintMessages; // << not tested, pulled out of code
var
msg: TMsg;
begin
while PeekMessage(msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE) do
DispatchMessage(msg);
end;
My final test was to add a Sleep to the AfterShow event and see the Form fully painted with empty db containers since the AfterShow events had not yet completed.
procedure TMainForm.AfterShow;
begin
inherited;
Sleep(8*1000);
......

Which is the best place to initialize code? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splash Screen Programatically
Show a splash screen while a database connection (that might take a long time) runs
Which is the best place to initialize code such as loading INI file? I want first to show the form on screen so the user know that the app is loading and ONLY after that I want to call lengthy functions such as LoadIniFile or IsConnectedToInternet (the last one is REALLY slow).
The OnCreate is not good because the form is not yet ready and it will not show up on screen.
I do this I DPR but not working always:
program Test;
begin
Application.Initialize;
Application.Title := 'Test app';
Application.CreateForm(TfrmTest, frmTest);
frmTest.Show; <---------------------- won't show
LateInitialize;
Application.Run;
end.
The form will not show until LateInitialize (4-5 seconds) is executed.
procedure LateInitialize;
begin
CursorBussy;
TRY
// all this won't work also. the form won't show
frmTest.Visible:= TRUE;
Application.ProcessMessages;
frmTest.Show;
Application.ProcessMessages;
frmTest.BringToFront;
frmTest.Update;
Application.ProcessMessages;
DoSomethingLengthy; {4-5 seconds}
FINALLY
CursorNotBussy;
END;
end; <--------- Now the form shows.
And yes, frmTest it is my only form (the main form).
After calling frmTest.Show, you can call frmTest.Update to let it render onscreen, before then calling LateInitialize. But until Application.Run is called, the main message loop will not be running, so the form will not be able to do anything else until then.
Another option is to use the form's OnShow event to post a custom window message back to the form via PostMessage(), then have the form call LateInitialize when it receives that message at a later time. That will allow the form to process painting messages normally until LateInitialize is called.
Anything that blocks the main thread for more than a few milliseconds/seconds really should be moved into a separate worker thread instead (especially things like IsConnectedToInternet). The main thread should be used for running the UI.
An easy way to do this, is to send a message to yourself.
I do this all the time
const
MSG_AFTERCREATE = WM_APP + 4711;
...
procedure OnCreate(Sender: TObject);
procedure AfterCreate(var message: TMessage); message MSG_AFTERCREATE;
...
Implementation
procedure OnCreate(Sender: TObject);
begin
PostMessage(Self.Handle, MSG_AFTERCREATE, 0, 0);
end;
procedure AfterCreate(var message: TMessage);
begin
//Do initializing here... the form is done creating, and are actually visible now...
end;
Variant 1: Use TTimer with a 1 second delay, run it from main form's OnShow
In TTimer do the initialisation
This will give time for most components to initialize and draw themselves
Variant 1.1: use message method in function and call Win API PostMessage (but not SendMessage aka Perform) from OnShow. This is seemilar but more cheap and fast. However that message "do init now" sometimes may be received before some complex component on the form would fully draw itself.
Variant 2: use threads (OmniThreadsLib or even plain TThread)
Launch it from MainForm OnCreate and let it prepare all data in background, then enable all needed buttons, menus, etc
That is truly the best way if you have long and blocking functions, liek you described IsConnectedToInternet.
Variant 3: use SplashScreen before showing main form.
That is good because users see that application not read yet.
That is bad for that very reason - people start feeling your program is slow. Google Chrome was told to draw their main form as picture in 1st moments just to make look "we are already started" even the actual control would be ready a bit later.
A long time ago in another forum far far away, someone posted the following to document the life cycle of a form. I have found it useful, so am sharing it here.
Create OnCreate
Show OnShow
Paint OnPaint
Activate OnActivate
ReSize OnResize
Paint OnPaint
Close query OnCloseQuery
Close OnClose
Deactivate OnDeactivate
Hide OnHide
Destroy OnDestroy
Try the OnActivate event.

Preventing crash when doing time consuming task with COM (SKYPE4COM)

I am using the Skype4COM control. My program is trying to delete around 3K contacts from my contact list in Skype using a For loop, however
1) It takes a lot of time
2) it may crash, with a "MyApp has stopped working"
My guess is that somehow I need to "slow down" what I am doing.
Would I do that with Sleep();? Because I am not sure if that is also gonna "pause" the connection between Skype and my program.
To summarize: I am doing an action with a huge ammount of entries, and because of that big ammount, my program is hanging for a long time, and eventually crashes (sometimes). Is there a way to prevent that?
Skype4COM is STA by the way.
Thanks!
Move the processing into a separate thread. Your problem appears to be that Windows thinks the app has stopped responding because it's not processing it's message loop.
Calling Application.ProcessMessages is the wrong solution, because it does a lot more than you might think. You can end up with problems with reentrancy, or things happening that you don't expect.
Make sure that the thread calls CoInitialize before it creates the COM object, and calls CoUnitialize when it's done. You can find examples of using COM in a thread here; the article refers to ADO, but demonstrates the use of CoInitialize/CoUninitialize.
EDIT: After the comments, I'm adding an example of receiving a custom message in a Delphi app. The thread will need access to the UM_IDDELETED constant; you can do this by (preferably) adding it to a separate unit and using that unit in both your main form's unit and the thread's unit, or simply by defining it in both units.
// uCustomMsg.pas
const
UM_IDDELETED = WM_APP + 100;
// Form's unit
interface
uses ..., uCustomMsg;
type
TForm1=class(TForm)
// ...
private
procedure UMIDDeleted(var Msg: TMessage); message UM_IDDELETED;
//...
end;
implementation
procedure TForm1.UMIDDeleted(var Msg: TMessage);
var
DeletedID: Integer;
begin
DeletedID := Msg.WParam;
// Remove this item from the tree
end;
// Thread unit
implementation
uses
uCustomMsg;
// IDListIdx is an integer index into the list or array
// of IDs you're deleting.
//
// TheFormHandle is the main form's handle you passed in
// to the thread's constructor, along with the IDList
// array or list.
procedure TYourThread.Execute;
var
IDToDelete: Integer; // Your ID to delete
begin
while not Terminated and (IDListIdx < IdList.Count) do
begin
IDToDelete := IDList[IDListIdx];
// ... Do whatever to delete ID
PostMessage(TheFormHandle, UM_IDDELETED, IDToDelete, 0);
end;
end;
if you are using a loop to delete each contact you can place a call to Application.ProcessMessages this should fix the issue
[edit]
the call should be in the loop

how to get the information that did when thread is paused

how can i get actions ,i did when my thread is paused after resumed (Sorry for my bad english )
ok i will explain with code
function mythreadf(p:Pointer):DWORD stdcall;
var i:Integer;
begin
for i:=0 to 1000000 do begin
if myevent.WaitFor(INFINITE)=wrsignaled
then
begin
if Form1.RadioButton1.Checked then ShowMessage('Checked');
Form1.Label1.Caption:=IntToStr(i);
end;
end;
end;
i am pausing and resuming my thread using resetevent and setevent
after i paused my thread by clicking resetevent button and then i checked radiobotton1 after that when resume my thread by using setevent again .dont send error occuring and applications closing :(
can any one help me in this issue
regards
Edit 1:
Error image
http://i49.tinypic.com/11r7nkn.jpg
Accessing VCL UI controls directly in a worker thread is NOT thread-safe (even ShowMessage() is not thread-safe. Use the Win32 API MessageBox() directly instead). All kinds of bad things can happen, including crashes. You must delegate your UI access to the main thread instead. The TThread class has a Synchronize() method for that purpose. Or you can use any other inter-thread synchronization of your choosing, such as by using SendMessage() to send custom messages to a hidden window created in the main thread via AllocateHWnd() or CreateWindow/Ex().
Your thread, as Remy says, should not be accessing the checkbox. Also it's bad programming style. Your background thread has a purpose? That purpose will help you find a name. If you create a class that inherits from TThread, you will get farther, faster.
interface
type
TMyElephantCountingThread = class(TThread)
protected
FResultStr:String; // holds something for later display on the user interface
FOptionChecked:Boolean; // set from main thread, to tell background thread whether or not a checkbox option is checked.
....
end;
....
implementation
....
function TMyElephantCountingThread.ElephantCounterResults;
begin
// all data fields in here is local to this thread
if FOptionChecked then
FResultStr := IntToStr(FIntegerValue);
end;
As you can see my code above uses only fields that belong to my thread object.
If FOptionChecked needs to be set equal to the value of Checkbox.checked, that must be done in the main thread.
You can not copy and paste write code from your foreground thread (which can access your VCL objects) into your background thread code (which can not safely access those objects), and not expect problems.

TThread.resume is deprecated in Delphi-2010 what should be used in place?

In my multithread application
I use TThread.suspend and TThread.resume
Since moving my application to Delphi 2010 I get the following warring message
[DCC Warning] xxx.pas(277): W1000 Symbol ‘Resume’ is deprecated
If Resume is deprecated what should be used in place?
EDIT 1:
I use the Resume command to start the thread - as it is Created with 'CreateSuspended' set to True and Suspend before I terminate the thread.
EDIT 2:
Here is a link the delphi 2010 manual
Charles if do you read the code of TThread class , do you find the answer.
TThread = class
private type
..
..
..
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure AfterConstruction; override;
// This function is not intended to be used for thread synchronization.
procedure Resume; deprecated;
// Use Start after creating a suspended thread.
procedure Start;
// This function is not intended to be used for thread synchronization.
procedure Suspend; deprecated;
procedure Terminate;
See this link RAD Studio 2010: Community pulse: The day after. (Part 2)
Edit:
If you need to synchronize threads, you can use a scheme based on TMutex, TEvent and critical sections.
Bye.
Use TThread.Start instead of .Resume
--EDIT--
Start can of course only be used with Delphi 2010 (and later, presumably) to start a thread that was created suspended (where you would have used Resume before).
Using Resume/Suspend (or corresponding WinAPI functions) for thread synchronisation is NOT recommended. See the discussion here (have a look at Barry Kelly's comments).
Suspend and Resume were (or used to be) potentially broken in the TThread class (if you look at the source you will see that the Suspend method directly and unconditionally sets a Boolean to indicated thread suspended state rather than more robustly deriving this state from the execution count on the thread handle. Ironically the Resume method does use this more robust indicator to update the suspended state Boolean).
This is possibly why they have been deprecated. It's also why I implemented my own class to encapsulate a Windows thread with a more robust suspend and resume mechanism as well as the ability to Restart a thread once it had completed.
I'm not sure why their deprecation is supposedly related to synchronization. Suspending and resuming threads is not necessarily related to synchronization, although I can see how it might be. It's interesting to note that the equivalent methods in the .NET framework Thread class are similarly marked as obsoleted. And the same comments w.r.t synchronization appear in the Windows API documentation for thread suspend/resume.
If using deprecated methods makes you nervous and you still wish to suspend/resume you could always use the Windows API to suspend and resume the thread by reference to it's handle.
Just in case all you wanted to do was get rid of the compiler hints
(1) To get rid of the compiler hint when Starting a Thread ...
replace
MyThread := TMyThread.Create(True);
MyThread.Resume;
with
MyThread := TMyThread.Create(True);
MyThread.Start;
(2) To get rid of the compiler hint when Stopping a Thread ...
replace
MyThread.Suspend;
MyThread.Terminate;
with
MyThread.Terminate;
Not a big deal at all. Beware of attempted obfuscation.
Thread behavior control code should lie with in a thread procedure. Use appropriate sync objects and corresponding API calls in order to suspend/resume thread execution. Doing it from outside is a dangerous practice. So there was a decision to depricate it.
Use
Suspended := False; // Resume;
or
Start;
You should create the thread as follows:
constructor TSignalThread.Create;
begin
// create event handle first!
FEventHandle := CreateEvent(
{security} nil,
{bManualReset} true,
{bInitialState} false,
{name} nil);
FWaitTime := 10;
inherited Create({CreateSuspended}false);
end;
This way a call to Start is not required.
See http://www.gerixsoft.com/blog/delphi/creating-threads for an explanation why this code works.
#mghie (a little late, I know)
take for example madexcept and alike. If your application crashes and a bug report is being shown to user, that means that the dialog waits for use input. If it so happens that the crash is a result of a thread action (not necessarily a thread crashing), if you do not suspend the threads, the screen will be filled with bug report dialogs.
example 2: logging. for any particular reason, I at least, had the need to log some threads execution state. That includes the current stack trace. Now, as you (should) know, you cannot do that while the thread is running because during the time you collect information about it, the threads keeps doing stuff so by the time you finish collection, the information collected will not be consistent. Hence, you need to suspend the thread.
And I can go on with practical examples on thread management. Granted, these are not things you do in every day programming, but at least the first example I am sure that many of you are using, even if you are not aware of the internals of it. Debuggers? again, you use them.
But indeed, in all these cases, TThread is not used, since the work is done on thread handles. So, indeed, a valid example of TThread suspend usage is hard to come by. But threads in general, that's another story.

Resources