postthreadmessage and peekmessage problem in delphi 2006 - delphi

I created a multichilded application. The application windows (W[n]: TMyWindows) are all the same and all have an private object class instance associated with them (E: TMyObject).
The child windows generate through this objects some messages. I have created in the main application two threads which process these messages depending on the content of the messages. For example lets have the following asynchronous calls:
W[1].E.Service(thread1service)
W[2].E.Service(thread2service)
the TMyObject.Service(servicetype) is
case servicetype of
thread1service: PostThreadMessage(thread1id,...);
thread2service: PostThreadMessage(thread2id,...);
end;
Now, in the Execute Method of each thread i have something like that:
while not terminated do
begin
...
if peekmessage(msg,0,thread1message_1,thread1message_n,pm_remove) then
process message
do other things;
end
All goes fine exept that the second thread doesn't receive any messages.
Do you have any idea why?

I would check to make sure that the range you are supplying to PeekMessage() is valid. Try putting zeros in instead to receive all messages, like this:
PeekMessage(msg, 0, 0, 0, PM_REMOVE)
If that doesn't work, I would check the result of the PostThreadMessage() function... It may be that the thread hasn't called PeekMessage() yet, that's what prompts windows to create the message queue for you.
As stated in this article (under "Remarks"), you can either check the result of the call to PostThreadMessage(), and Sleep() if it fails, or use an event to signal to the main thread that the child thread is ready to receive messages.
HTH,
N#

So, I had to give up as I didn't find any rational explanation.
I've decided to send messages using a critical section with event signaling to tell the working threads that they have a message to process. Unfortunately, this means that the main thread have to check that the working thread processes any message before sending a new one.

I know this is an old question, but I have just had a similar problem in our code. We are running Delphi 2006 on Win 7 64-bit and the code in question involved a DLL communicating to a separate application via peekmessage/postthreadmessage.
I eventually managed to trace the issue down to administrator rights being granted either to the application or to Delphi. Compatibility mode also causes the problem to surface, as it requires admin rights to be granted. If admin rights are granted, the admin thread could communicate to the non-admin thread, but the non-admin thread could not then post a message back to the thread with admin privileges. The PostThreadMessage call on the non-admin app was reporting success, but the message never appeared in the target app's message queue.
I haven't solved the problem, but fortunately was able to run the application in normal mode, so it wasn't an issue other than the lost time in chasing it down.

Related

How to immediately completely stop an application and show a message?

When my application needs to make an emergency stop, I could call Halt or ExitProcess to terminate it immediately. This shouldn't happen quietly, though; the user needs to be shown a message. Therefore I looked to FatalAppExit but was surprised that it keeps everything (timers, threads) running until the user has closed the dialog.
I understand that showing a UI owned by the process requires the process to keep running. The UI does not need to be owned by my process, however. The dialog presented by FatalAppExit seems to be owned by Windows, even though it keeps the process running as well.
The main problem with FatalAppExit is that it's blocking—I want the dialog but not wait for confirmation—so I still can't terminate right after. To circumvent this, I'd have to start a thread that calls FatalAppExit, wait for a bit and then terminate the process. Not liking the race condition there.
I could also launch a process of my own to show the message, but I'd rather not if Windows can handle it.
Does Windows provide means to both terminate and show a friendly message at the same time? Any other suggestions to handle this as cleanly as possible?
As far as I know the only option here is to start an external process that displays the message and terminate immediately. You could write your own program for that purpose (which might be the easiest option) or you could start a batch file like this:
msg "%USERNAME%" %*
This sends a message to the given user (%USERNAME% is the currently logged on user) and uses all parameters passed to it as the actual message.
Personally I would write my own program, so I could write a log entry and do other stuff if it becomes necessary later.
You can have a global variable, such as
var ShutdownMessage: string;
When you need to terminate with an error, do:
ShutdownMessage := 'Error occured';
Application.Terminate;
and in the dpr file after Application.Run:
if ShutdownMessage <> '' then
MessageBox(0, PChar(ShutdownMessage), 'Error', MB_OK or MB_ICONERROR);
Then the message will be shown after all forms closed and main loop exited.
Or, if that fails, you can try to raise an exception after Application.Run - it should be propagated to OS

Sending a message to an application running on a secondary logged in user account

I'm trying to send a message to an application running under a different user account (a user that is also logged in with a different account on the computer, using quick user switch on XP and later, and executed the application).
The background is that my application can update itself, but in order to do that all running instances must be closed first.
The instances need to be shut down (instead of just killing the process), so the updater does that by sending a custom message to them (with SendMessage). In order to send a message I need a handle to the main window of the process.
This works fine using EnumWindows - as long as the instances are running under the same user account, because EnumWindows does not list windows belonging to a different user.
So I tried a different approach. I used CreateToolhelp32Snapshot to first list all running processes on the system, and then iterating through the threads calling CreateToolhelp32Snapshot again. With those thread ids I could then list their windows using EnumThreadWindows.
Once again this works fine, but.. once again only for the current logged in user. The problem here is that even though CreateToolhelp32Snapshot lists process ids belonging to a different user it does not list thread ids belonging to them. The code for this is a little lengthy, but if it's required I can edit it in - please leave a comment for that.
So, how could I get the main window handle of my application running on a different logged in user account?
Use something that's known to work across sessions; This kind of stuff is often used for desktop-service communications, so look for that if you want to google. Here's my suggestion:
Create an event that will only be used to trigger the "need to shut down" state. Use the CreateEvent function make sure you start your name with Global\ so it's valid across sessions.
On application startup create a thread that opens the named event (uses the same CreateEvent function, pay close attention to the ERROR_ALREADY_EXISTS non-error). That thread should simply wait for the event. When the event is triggered, send the required message to your main window. That thread can easily and safely do that because it's running inside your process. The thread will mostly be idle, waiting for the event to be triggered, so don't worry about CPU penalty.
Your application updateer should simply trigger the named event.
This is just one idea, I'm sure there are others.
Pipes are overkill. A global manual-reset event (e.g. "Global\MyApplicationShutdownEvent") which causes application instances to kill themselves should be enough.
At the risk of being scoffed at, have you looked at zeroMQ, this is a perfect use for it and it very reliable and stable.
There is a Delphi wrapper

try/except doesn't seem to capture exceptions - Delphi Service Application

I have a service written in Delphi 2007 in which I'm trying capture any unknown exceptions. Assigning a method to the on exception doesn't seem to work ('Forms.Application.OnException:=UnknownApplicationException'). The 'UnknownApplicationException' doesn't appear to get called - I attribute this to the fact that there is no form in the application so the method never actually gets assigned. Aside from this, I've also tried creating an exception on a timer (after commenting out 'Forms.Application.OnException:=UnknownApplicationException' so that it does not interfere). The timer triggers 60 seconds after the service has started up:
procedure TProcessScheduler.Timer1Timer(Sender: TObject);
begin
try
Raise Exception.Create('THIS GIG SUCKS');
except
LogEvent(Name,rsUNKNOWN_EXCEPTION,EVENTLOG_AUDIT_FAILURE,0);
ExitCode:=-1;
Halt;
end;
end;
The exception never seems to get captured - the service starts up and after 60 seconds when this timer triggers, I hear a windows error sound but don't see any error dialog - perhaps this could be due to the fact that the application is a service? The 'Halt' never gets called and the application keeps running (i assume its waiting for someone to click ok on the invisible error dialog that it created). Any ideas why the code under the 'except' doesn't get called? Thanks in advance! KP
Reassigning Forms.Application.OnException is a bad idea, as TServiceApplication.Run() does this itself. You either do it before, then your assignment won't have an effect, or you do it afterwards, in which case you remove the exception handling mechanism that has been put into place.
If you leave the handling in place, then all exceptions will be logged to the Windows Event Logger, which seems a reasonable thing to do from a service.
A couple of notes:
As you are raising an exception within a try-except block, it should not trigger any Application.OnException handler, simply because the exception isn't unhandled.
How have you determined that the Halt doesn't get called? Does the exception get logged through your LogEvent?
In a Service application ExitCode and Halt don't function the way you would expect them to in a normal windows application. A service isn't stopped by calling halt, it should be stopped by going through the Windows' Service Control Manager.
If the except part of your try-except block is indeed not reached, it means that Windows has cut in because something has happened that it isn't happy with. That could be something in the LogEvent method you are calling. If that shows a dialog or if that raises an exception as well, the ExitCode and Halt won't be reached.
A service doesn't normally have a desktop associated with it, so showing dialogs isn't going to work.
If you need the service to show dialogs (bad idea by the way, services are intended to run without user interaction), you need to make it interactive and have it run under another user account than the normal "system" account that services run under. You do this through the services manager.
Why are you setting Forms.Application? AFAIK a service uses the Application variable declared in SvcMgr, which is declared as:
var
Application: TServiceApplication = nil;
Moreover a service should not display any dialog, it may not have access to the user desktop, and your dialog will hang the service. There are ways to display a dialog anyway, but services could also run when no human user is watching the screen.
Log events to the event log (or if you don't like it to a file, but the event log has several useful features, including remote access).
I create my own version of the SvcMgr.pas file to eliminate the in-place hook to the Application global exception handler so that I can instantiate my own. I do this because 1) I could find no other simple way of doing this, and 2) since this unit is a stand-alone unit that is only included with Windows Services then the effect on other units is minimal. You can download the code from my web-site to see how this works.

Delphi - Message loop for Form created in DirectShow filter goes dead

I have a DirectShow filter created with Delphi Pro 6 and the DSPACK direct show library. I'm running under windows XP. I've tried creating the form dynamically when the container class for the DirectFilter has its constructor called, passing NIL into the constructor as the AOwner parameter (TMyForm.Create(nil) and then calling the Form's Show() method. The form does show but then appears to stop receiving windows messages because it never repaints and does not respond to input. As a test I then tried creating my own WndProc() and overriding the Form's WndProc(). My WndProc() did get called once but never again.
I'm guessing it's because I'm a DLL and the context that I am running in is not "friendly" to the window message handler for the form; perhaps something to do with the thread that calls it or whatever. If someone could give me a tip on how to solve this or what the proper way to create a persistent window is from the context of a DirectShow filter I'd appreciate it. Note, as I said the window needs to be persistent so I can't create it as a Filter property page.
Thanks,
Robert
I can't help you with the DirectShow filter specifics, but I feel that some general information about windows and message handling might help.
Windows have thread affinity, which means that all messages for a window will be handled in the context of the thread that created it. That means that this thread needs to have the standard message processing loop, the low level equivalent of Application.ProcessMessages(). Both messages from the same and from other threads will be queued in the message queue of the creating thread, and the message loop will get them, (optionally) translate them, and dispatch them to the window handler of the target window.
What you are describing could be caused by either
not having a message processing queue in the thread that creates the window, or
creating the window in the wrong thread
(Note that these are essentially the same, but stated like this it becomes apparent that there may be different problems that cause this, which need to be fixed in different ways - either the window needs to be created in a different thread, or a processing loop needs to be created in the thread.)
You need to find out which of the two causes your window not to process messages. You don't necessarily need to override WndProc(), message handling methods for distinct messages will work (or not work) the same. That your WndProc() was called once doesn't really tell you much, because under some circumstances messages sent from the same thread will be handled without the message loop, by calling the window proc directly.
Since your filter resides in a DLL I don't think that creating your own message loop would be the right thing. This works for a modal dialog, which will be created, the message loop will run until the dialog is closed, and then the message loop will terminate and the DLL function will return. It will not work for a DLL exported function that will be called and needs to return all while the message loop is still running. I assume the framework that creates and calls those filters will handle the message loop as well. However, that is a gut feeling, not knowing about DirectShow filters this may well be wrong.
What might help you to debug this is a tool like Spy++ from Visual Studio, with which you can show information about windows, log messages sent to them or to all windows in the same process or thread, show window hierarchies and do a lot of other interesting things. If you don't have that, there are a lot of clones (some freeware) on the net, which Google should turn up. Trying to show the messages sent to all windows of the same thread or process should tell you whether a message loop is running. You should also be able to get more information by running SysInternals Process Explorer or similar tools.

Multithreaded (TThread) Delphi application will not terminate

I have written an application (using Delphi 2009) that allows a user to select a series of queries which can be run across a number of different systems. In order to allow queries to be run concurrently, each query is run in its own thread, using a TADOQuery object. This all works fine.
The problem that I have is when I try to close the application when a query is still running (and therefore a separate thread is active). When I create each thread, I record the thread's THandle in an array. When I try to close the application, if any threads are still running, I retrieve the thread's handle and pass it to TerminateThread, which should theoretically terminate the thread and allow the application to close. However, this doesn't happen. The main form's onClose event is triggered and it looks like the application is closing, but the process remains active and my Delphi interface appears as though the application is still running (i.e. "Run" button greyed out, debug view active etc.). I don't get control back to Delphi until I manually end the process (either Ctrl-F2 in Delphi or via Task Manager).
I am using TerminateThread because the query can take a long time to run (a few minutes in cases where we're dealing with a million or so records, which in the end user environment is perfectly possible) and while it is running, unless I'm mistaken, the thread won't be able to check the Terminated property and therefore won't be able to end itself if this were set to True until the query had returned, so I can't terminate the thread in the usual way (i.e. by checking the Terminated property). It may be the case that the user wants to exit the application while a large query is running, and in that case, I need the application to immediately end (i.e. all running threads immediately terminate) rather than forcing them to wait until all queries have finished running, so TerminateThread would be ideal but it isn't actually terminating the thread!
Can anyone help out here? Does anyone know why TerminateThread doesn't work properly? Can anyone suggest anything to get the threads running large ADO queries to immediately terminate?
You should be able to cancel an ADO Query by hooking the OnFetchProgress event, and setting the Eventstatus variable to esCancel. This should cause your query to terminate and allow the thread to close gracefully without having to resort to using TerminateThread.
Instead of using threads with TADOQuery, maybe you should consider using the async options of ADO.
ADOQuery1.ExecuteOptions := [eoAsyncExecute, eoAsyncFetch, eoAsyncFetch];
Then when your application close, you can call :
ADOQuery1.cancel;
As you can read in the msdn using TerminateThread is dangerous.
TerminateThread is a dangerous
function that should only be used in
the most extreme cases. You should
call TerminateThread only if you know
exactly what the target thread is
doing, and you control all of the code
that the target thread could possibly
be running at the time of the
termination.
But it also is very effective in killing threads. Are you sure you are right in your conclusions? Maybe the thread is killed, but another thread is still running? Maybe your handles are not thread handles? Could you show us some code? Or even better: A small working example we could try for ourselves?

Resources