Executing delegate in existing thread

Miky_Mike

Member
Joined
Aug 5, 2009
Messages
8
Programming Experience
5-10
I have searched the internet for a basic question, but not found the answer yet.... Here it is:

- I have a GUI which executes on the GUI-thread. Further I have another thrad which does video processing using DirectShow (this is COM).
- Now I want to execute a function on the same thread as where the videoprocessing is executing. This is initiated by the GUI-thread. Touching the COM-referenced object goes wrong if a execute the function from another thread (I understand that).
When a call the function from the same thread everything goes fine. But to do this I have the poll some flag-bits in the mainloop, and that is not a 'pretty' solution...

All discussions on the internet are about how change the GUI from a different thread.

I have tried several things:
1) Invoke the function using a delegate. This doesn't wordt, since the function is executed in the GUI thread. (checked bu ThreadID's)
2) BeginInvoke the function using a delegate. May be .net executes the function in a original thread where the object has been created. This does also not work: .net used random threads (probaby from the threadpool)
3) ISynchronizeInvoke, Threading.SynchronizationContext and some other features seems only to work on the GUI thread only...:(

The question: Is there a way to Post, Send of Invoke a delegate on the specific thread (for example by a reference to this thread or threadID)

Thanx in advance! Mike
 
While the purpose of most of the examples you've seen is to update the existing UI with data obtained on a secondary thread, what they are actually doing is using a control to marshal a method call to the thread that owns that control. All you have to do is create a control on that other thread and you can do the same thing. You simply call the Invoke method of that control and the call will be marshalled to the thread that created that control, rather than the thread that created your UI. The control doesn't have to be shown or used in any other way BUT I think you'll find that you have to call its CreateHandle method at least. Invoke is based on the thread that owns the handle so there has to be a handle.

Note that this solution is a bit of a hack. There are more professional ways to do it but I haven't investigated them. This option is fairly easy and gets the job done so, if it's a one-off, it's the way I'd go.
 
Thanx jmcilhinney for your reply. It seems to be a good way to solve the problem. Simple create a control on the not-GUI thread and invoke the delegate on that control. :D

Dim LocalControl as new Label
Me.Controls.Add(lControl)

But when I attempt to create a control (f.e. a label) to the control collection, I get the error message 'Invalid Operation Exception'.

The location in code where I execute above statements are not in the GUI-thread, but the imaging thread.

Dim LocalControl as new Label
Me.Controls.Add(lControl)

What goes wrong here??

I am new on VB.net (I have developed software for 10 years using VB5 and VB6, but I have never used threading...)

Mike
 
You're not supposed to add the control to the form's Controls collection. That would require accessing the form's handle, which you can't do if you're not on the thread that owns it. This new control exists only for one purpose and it doesn't need to be in the form's Controls collection for that.
 
@Newgay: usefull other info... but it accesses mainly how to change GUI controls from another thread. I need the opposite: I have a thread without any control and I have to invoke a delegate on that thread.

@jmcilhinney: I have managed to obtain a new window handle using the NativeWindow class. I have set several properties:

Dim instance as New NativeWindow
dim cp as CreateParams
cp.Caption = "Dummy Window"
cp.ClassName = "STATIC" '(Textbox)
cp.Style = SS_SIMPLE
instance.CreateHandle(cp)

Now instance.Handle is a value other than null, seems to be okay!

Before I can invoke the control I have to create a Control from the handle:

mControl = Control.FromHandle(instance.Handle)

But this return nothing... (no error)

Why does FromHandle not work??
 
Last edited:
Control.FromHandle gets the existing control that is associated with the specified handle. In your code there is no existing control associated with that handle so Control.FromHandle returns Nothing. That handle is associated with a NativeWindow and a NativeWindow is not a control. When I said create a control that's exactly what I meant:
VB.NET:
myControl = New Control
Having said that, now that I think about it, I don't really see how that's going to help you anyway because, unless that thread has a message loop, you're not going to inject a method call into it anyway. Most threads will either loop continuously, in which case it will never get to your method call, or they do their job and terminate, in which case it will never get to your method call.

I think you need to explain in more detail what exactly you're trying to achieve.
 
Yeah, I have just read now that the FromHandle does only work in the system.windows.forms context.

What I have to do the following:
- I have a GUI
- I have a (second) helper-thread on which some code is running that has to do with imaging (DirectShow). This thread has ApartmentState=STA.
- The second thread is created en launched from the Form_Load event. It is required because otherwise the GUI is not responsive (i.e. stays in the Form_Load when executing the endless loop there...).
- After some startup code and initialisation of the DirectShow graph, the code on the helper-thread runs in a endless loop, waiting for callback from the graph and doing some networking. Everything works fine. I have managed to set the Control for a PreviewWindow by delegating some code on the GUI-thread.

- During Initialisation of the graph I gathered some object references, such as to IAMVideoProcAmp. Using these references I am able to change the Contrast etc. of the camera's. This also works fine.
- From the change event of a Control on the GUI I want to call a function 'ChangeContrast', which is in the same class as the initialisation function of the graph.
- BUT: I have to call the 'change contrast' function on the same thread as the graph is running on. Otherwise the nothing happen or the application crashes.
- The references are still available if I execute from another thread, but an exception occurs when I access the references. I think that the COM -object not allow to be references from another thread.

I hope my problem is clear now :D
 
This is how it can be done, but I'm not sure if it is necessary...

keep a control for reference, to be used to invoke:
VB.NET:
Private ref As Control
in worker thread create the control and assign it, force the handle to be created:
VB.NET:
ref = New Control
ref.Handle.ToInt32()
from UI thread invoke from the reference:
VB.NET:
ref.BeginInvoke(...)
since worker thread has no message loop you have to call DoEvents during the worker loop or between sequential instructions to allow waiting methods to execute on that thread:
VB.NET:
Application.DoEvents()
 
Wow! It works!

The function is invoked on the right thread (checked by ID) and the COM objects are referenced correctly.
At the end, the solution was surprisingly simple :D

I will thank everybody who had contribute to this thread!

Mike
 
One question: why must the handle convered to Int32. Without this statement I get an 'invalid cast exception' when attempting to invoke the delegate... With the conversion everything works fine.

Mike
 
One question: why must the handle convered to Int32. Without this statement I get an 'invalid cast exception' when attempting to invoke the delegate... With the conversion everything works fine.

Mike
As explained the controls handle must be created in the worker thread, CreateControl method can be used, and if you read that help topic you'll understand that ref.Handle.ToInt32() is just a way to do it with less code. Perhaps ToString is better, or this:
VB.NET:
Dim h As IntPtr = ref.Handle
 

Latest posts

Back
Top