Winforms/ActiveX cross threaded calls - winforms

I have an application wherein I am hosting multiple types of content (images, PowerPoint presentations, videos etc) in a kiosk-type app. The user has to be able to page back and forth between these bits of content, preferably using gestures of the touchscreen on the kiosk, i.e. tap one side of the screen to go forward, the other side to go back.
Unfortunately, the controls that display the content could have further nesting, so I'm using a Win32 mouse hook to capture mouse clicks, checking if they are within a specified region. This works great. Unfortunately these click events are (indirectly) calling methods on the ActiveX control I'm using to host PP presentations (DSOFramer), and it's causing this nasty COM exception:
An outgoing call cannot be made since the application is dispatching an input-synchronous call. (Exception from HRESULT: 0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))
My best guess is that the low level mouse hook is calling from a different thread, because if I make the call directly from the Winforms UI thread, there's no problem. I tried the standard Winforms Invoke/BeginInvoke with no success.

I was using the typical Winforms cross-thread pattern:
if(InvokeRequired)
{
Invoke(new Action(DoStuff));
}
else
{
DoStuff();
}
Of course the control I'm calling from has no idea of the AX control, so I need to explicitly invoke the action. It also needs to use BeginInvoke, so the above becomes:
BeginInvoke(new Action(DoStuff));
Works now. Oops!

Related

GUI - Linux - C - how click events are managed?

Context:
Reading some GUI libraries on Linux 64.
I've always used libraries (or done headless applications). Now, it is time to move on and complete my understanding.
Question:
I am not sure how the system knows when one clicks a button on a gui app.
It seems that poll/select/epoll helps but I don't get the whole picture.
Here is what I think:
When the gui is created, it knows where the buttons pixels are, so it attaches each of them to an event handler (epoll...), OR just one callback to react to a click in this app.
When I click a button, epoll calls the callback for this application which manages the click events. the callback iterates the list to find the button.
Of course, there are optimisations, like dividing the screen in multiple squares for example and many other things.
But, am I correct ? is this the logic under the hood ? Is X11 more involved ?
Thanks
Ok, after your comment: I'll bite:
No, you are not right.
But how does that increase your knowledge now?

How to get list of open windows, including DLL in a Delphi application

My application can load DLLs which basically hold another windowed applications.
It can only open one DLL window at any time.
I have encountered a situation when DLL window shows a Message box and/or my main app shows a message box or a modal form, and by deactivating the application (switching to another one) and then activating it, moves all the windows in random(?) z-order, thus making DLL form with it's message box go behind the main form. Main forms message box goes behind the main form.
This results in a non-responsive application. Can't click anything, can't close, can't minimize. Have to kill through Task manager.
In Delphi, i see there is Screen object and it has a list Forms. I checked it and saw that it holds all the forms my application has currently open (Even the message box, which is the result of ShowMessage(), it has no name, but i can see the ClassName).
So far it was good, i could iterate through forms and use SetWindowPos to tell them the correct z-order, however, i cannot do this for the DLL application. Screen does not have this form in the list.
How do i control z-order of the DLL forms?
The DLLs are built using either Delphi, C++, WPF.
You must follow the OS way of ordering the windows (with the use of a handle). A DLL's application handle is zero by default, so you need to define it when showing modal dialogs.
According to documentation Vcl.Forms.TApplication.Handle:
Note: When writing a DLL that uses VCL forms, assign the window handle of the host EXE's main window to the Handle property of the DLL's global Application variable. This makes the DLL's form part of the host application. Never assign to the Handle property in an EXE.
To maintain the Z-order of the dll modal forms, do as Peter Below suggests:
// In the dll
var
oldWnd: HWND;
begin
oldWnd := Application.Handle;
Application.Handle := HandleOfHostform; // <-- Pass the exe host form handle
try
.... create and show the DLL form
finally
Application.Handle := oldWnd;
end;
end;
The modal form should be created without an owner, TMyDllForm.Create(nil).
I'm not 100% sure Delphi-7 correctly resolves the handle in a DLL this way.
Another approach would be to override CreateParams for the form object, as suggested here.
procedure TMyDLLForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := HandleOfHostForm;
end;

WPF application calls an API that needs a message pump; Dispather.Run() causes problems

I have a WPF app that uses a non-WPF vendor library. My app does not receive any events that the library fires. I've been told that this is because I need a message pump.
In another (very similar) question, the accepted answer suggested using System.Windows.Threading.Dispatcher.Run().
When I add in that call, however, my window won't pop up-- the app is effectively backgrounded and I have to shut it down with Task Manager.
I'm really stumped here, and I'm not even sure how to investigate it. Any help would be greatly appreciated.
You already have one if you use WPF, there's no other way that it can get any Windows notifications. Every WPF app starts life with a call to Application.Run() on the main thread. It is usually well hidden, auto-generated in the bin\debug\app.g.cs source code file. Application.Run() in turn calls Dispatcher.Run()
Your vendor is correct, without a message loop many COM components go catatonic. But since you have one you need to look for the problem elsewhere. Don't use the component on threads.

'Cross-thread operation not valid' does not kill WinForms application (and it should)

Update: here is an MSDN article How to: Make Thread-Safe Calls to Windows Forms Controls. It states:
The .NET Framework helps you detect
when you are accessing your controls
in a manner that is not thread safe.
When you are running your application
in the debugger, and a thread other
than the one which created a control
tries to call that control, the
debugger raises an
InvalidOperationException with the
message, "Control control name
accessed from a thread other than the
thread it was created on."
This exception occurs reliably during
debugging and, under some
circumstances, at run time.
My previous experience was that the exception was thrown at run time, too.
Thanks to Spence for pointing me in the right direction.
I have a pretty common error in WinForms app: background thread accessing UI controls directly instead of using Control.BeginInvoke().
My problem is the following: I see the InvalidOperationException "Cross-thread operation not valid: Control 'uxCheckStatus' accessed from a thread other than the thread it was created on." in debugger on background thread, but then it is swallowed somewhere in WinForms internals.
I expect it to kill the background thread and entire application.
Moreover, the code that is triggering it uxCheckStatus.Text = "success"; sometimes gets executed during/after exception is thrown i.e. label text reads 'success'! I'm basically lost. Anyone else experiencing this behavior?
I reproduce it on completely new WinForms solution with 1 button, both using ThreadPool and Thread for evil background thread.
If I throw a new InvalidOperationException() on background thread, it does kill the application. So my only guess is that WinForms handles this specific exception somewhere, but I cannot find references to this behavior on the web.
I run .NET 3.5, VS 2008.
THis is by design. This is a coding error, not a runtime error. THe developers of Winforms decided that from .Net 2, they would implement code to check for the cross thread code and then fire an MDA. The MDA isn't an exception though, it's a check for badly designed code.
Additionally the MDA doesn't fire when your code is in release mode, it will just randomly fail every so often, the MDA is to help you at test, not during release.
I'm assuming that you are rewriting a badly written application to invoke onto the threads and you were hoping that the exceptions would catch for you, I have a suggestion:
Update your event handlers for GUI stuff to look like so:
public void button_clicked_handler(object sender, EventArgs e)
{
if(this.InvokeRequired)
{
this.Invoke(delegateToThisMethod)
}
else
{
//perform method
}
This pattern will catch all your methods and make it seamless for cross thread ops. If the threads are directly accessing code, this is a little tougher. You can get around this by renaming a control, then creating a property to the control, where you can then apply the invoke pattern to it. I've had to do this to troubleshoot some very funky cross thread stuff before.
EDIT:
Just wanted to clarify that checking the synchronisation context of the current thread and the Win Forms thread is a costly operation. Thus the reason they implemented the MDA is so that you find it in debug but that your release mode code isn't slowed down on EVERY access to EVERY property or method of a windows forms control.
I don't know of any specific documentation for how/why WinForms handles this exception. However, if you want to gracefully shut down your application when this happens, consider a global exception handler.

WPF Application that Listens for Commands Even When not the Active Application

I would like to configure a WPF application to function in a similar way to SlickRun. I would like to be able to minimize the application to the taskbar, then while in any other program, press a key command (ex: ALT + X) and have my application appear to the user.
Can someone point me in the right direction?
Your best bet is to use RegisterHotKey(). That works by sending the WM_HOTKEY message to the HWND you passed in. Since WPF doesn't expose its windows' message loop to developers, you'll probably need to get your hands dirty with some interop and create a message only window to receive the hot key messages.

Resources