How to marshal to UI thread in managed code

G

Guest

Hello,

I have a worker thread that needs to call a method that only works on the
main/UI thread. One way to accomplish this in managed code is to use
Control.Invoke. However, in my case I don't have a .NET UI control from
which I can call Invoke. I have tried to create a temporary, invisible
Windows form and call Invoke against this, and while this sort of worked, it
highlighted additional problems (which I have not resolved) and is generally
not a very clean solution.

If I were writing in unmanaged code, I would likely use
CoMarshalInterThreadInterfaceInStream. I could also post a message back to
the main thread. Is something like this possible in managed code or are
there ways other than Control.Invoke to pass an interface pointer to a
different thread?

One other potential challenge is that my code is not responsible for
starting the secondary thread; it is started by the framework in which my
code executes. For a detailed discussion of what exactly I'm trying to
accomplish, see
http://groups.google.ca/group/micro...onitorselection&rnum=1&hl=en#153ce7d2f03e67e3.

Thanks!
Notre
 
G

Guest

Hi,

Notre Poubelle said:
Hello,

I have a worker thread that needs to call a method that only works on the
main/UI thread. One way to accomplish this in managed code is to use
Control.Invoke. However, in my case I don't have a .NET UI control from
which I can call Invoke. I have tried to create a temporary, invisible
Windows form and call Invoke against this, and while this sort of worked, it
highlighted additional problems (which I have not resolved) and is generally
not a very clean solution.

If I were writing in unmanaged code, I would likely use
CoMarshalInterThreadInterfaceInStream. I could also post a message back to
the main thread. Is something like this possible in managed code or are
there ways other than Control.Invoke to pass an interface pointer to a
different thread?

One other potential challenge is that my code is not responsible for
starting the secondary thread; it is started by the framework in which my
code executes. For a detailed discussion of what exactly I'm trying to
accomplish, see
http://groups.google.ca/group/micro...onitorselection&rnum=1&hl=en#153ce7d2f03e67e3.

Thanks!
Notre

If all you need is synchronization against non UI code, try the lock
operator to make code MT safe or use other .NET synchronization classes like
Mutex or ManualResetEvent and AutoResetEvent.

Honestly I don't see where your program is going. You want to call something
and you can only do it on the main UI thread but there are no controls not
even a form? Then why *do* you have a UI thread? It is hard to give advice if
the program or the intent is unclear.

Kind regards,
 
G

Guest

Hi Tom,

Thank you for your reply. I am writing a VSPackage (a DLL that extends
Visual Studio). My package does not introduce any UI of its own. As my DLL
runs inside Visual Studio, there is of course a UI, but this UI is managed by
Visual Studio. None of the core UI elements in Visual Studio are written
using managed control elements; so I cannot just get a handle of some control
in the Visual Studio UI and call Control.Invoke on it.

As described in the other post, I need to use methods on the
IVsMonitorSelection interface. Visual Studio has an architecture where you
can request a service, which gives you back an interface, such as
IVsMonitorSelection. As I am integrating with Visual Studio, there are
certain scenarios (such as when the build completes) where my DLL is called
back on a thread other than the main UI thread. In this case I need to
perform some logic that requires the services provided by the
IVsMonitorSelection interface. Unfortunatey, the IVsMonitorSelection
interface is only designed to work on the main UI thread. Therefore, I need
to switch thread context back to the main UI thread to use the
IVsMonitorSelection interface. One way to achieve this is to create a hidden
Windows Form of my own and call form.Invoke. This is not the cleanest
approach (I hope!) and has caused some secondary problems (see the other post
for details). So, I am looking for some way to do what I used to be able to
do in unmanged code: marshal an interface pointer to my own thread. Or, if I
knew how, I could post a message to the main UI thread where I could call
IVsMonitorSelection.

As noted, I don't explicitly create the worker thread, so this could add
some complexity to the problem.

Hopefully this clarifies the goal of what I'm trying to achieve.

Notre
 
P

Peter Huang [MSFT]

Hi

From your description, I understand that you have discussed the VSIP
problem with our another SP in that google link your provide.
Since I am not familar with IDE extension development, based on my
knowledge about thread marshaling in .NET, so far we do use Control.Invoke
to marshal the call across the threads, which is internally implemented by
SendMessge to the thread where the control lies. As for commonly COM
apartment and thread access is implement ed internally by CLR underlying.
There is no such an equivalent .NET call with
CoMarshalInterThreadInterfaceInStream related call.

If the Control.Invoke did not work for you, I think you need to contact
MSPSS directly.
http://support.microsoft.com

If you still have any concern, please feel free to post here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Charles,

Thank you for your reply. I don't see the attached example (maybe it's the
MSDN newsreader that's blocking it). Would it be possible for you to email
it to me? My email address is (e-mail address removed); please remove
the .online from the address.

Thanks,

Notre
 
G

Guest

Hi again Charles,

I used Outlook Express (rather than the web-based news reader) and was able
to get your attachment, so no need to email it to me. Thank you!

I'm rather confused by the example though. Not being a VB expert, I may be
reading the sample wrong, but it seems to me that the code sample is starting
a new worker thread and when the worker thread completes, it calls a delegate
that's handled on the form. This works great in your example.

My problem is, that I don't have a form or anything else that dervies from
Control, from which I can call Invoke. My application doesn't create any UI,
and the UI that drives my code is not managed, so I can't grab hold of
anything and reuse it for the purpose of calling Invoke.

Notre
 
C

Charles Law

Hi Notre

The principal of the example is that you don't need to know the caller in
order to raise an event on its own thread.

The key is in OnCompleted(), which would run on your worker thread. You will
see that it does not know anything about the main thread, but still manages
to raise an event on it.

Is that what you are trying to achieve, or have I misunderstood?

Charles
 
G

Guest

Hi Charles.

I guess I've got two things in mind. One, my worker thread shouldn't know
about the caller. Your example does a good job of demonstrating that.

The second thing is not so much a goal as a constraint. My code does not
create a .NET UI nor does it have access to the .NET UI anywhere else. In
your example, although the worker thread doesn't know about the main UI
thread, (I believe) it does know that there's a Windows Form control, from
which Invoke can be called to switch execution to the main thread. I can't
do this, because no Windows Form nor anything else deriving from Control
exists. So, there's nothing on which I can call Invoke. Given this, I
cannot use Control.Invoke; I must use some alternate approach like using
CoMarshalInterThreadInterfaceInStream (in unmanaged code) or posting a
message to the UI thread (don't know how to do this in managed code).

Notre
 
G

Guest

Hi Charles,

Thanks for the response and the link. I did review the reference, but to be
quite honest I don't know if I followed everything that was said there.

I'm not sure if I could implement the ISynchronizeInvoke interface. The
only implementation I could find of this was in System.Windows.Forms.Control.
I started to look at the Invoke method with a disassembler, but got lost in
all the details. I'd hate to have to redo all the work MS did in
implementing this, although maybe that's the only way, short of creating a
temporary form and (somehow) resolving the other problems that I've run into
using that approach.

Notre
 
S

sean.j.forbes

Notre,

In that thread on Joel's form, I was talking about creating an
implementation of ISynchronizeInvoke for worker threads. I'm not sure
that would help your current problem, however, as you are trying to
marshall back to the main ui thread.

If you are using .NET 2.0, I think that there is some static class that
lets you marshall to the main ui thread without a Control. I haven't
gotten to play much with 2.0, but I remember stumbling on something
like that when I was trying 2.0 out... I'm taking a breif look at
MSDN2, but I can't seem to find it right now.

Sean
 
G

Guest

Hi Sean,

Thanks for your reply. I am using .NET 2.0, so if such a static class does
exist, it would be perfect for my needs! I'll have a look around in the docs
and if I can't find it, I'll start a new discussion thread to see if anyone
else knows about it.

Notre
 
C

Charles Law

Hi Notre

I think, as has probably been said elsewhere, the reason why forms and
controls can be so readily interrupted is that they have a message loop. If
we are just talking about a bespoke class then, unless it has an idle
period, it cannot be interrupted. The class would have to, periodically,
look for some signal that another process was trying to do stuff. If it is a
worker thread then it could explicitly look for a signal each time round its
processing loop.

Charles
 
S

shay azulay

Hi Sean

I am having the same problem: i need to raise events from worker thread
to the main thread(not UI thread) in the main thread's context.

The static class that was suggested earlier is probably:
SynchronizationContext that works perfectly with the UI thread but ONLY
with it(probably because it works with the windows message queue and
worker threads does not have that). although docs mentioned otherwise.
BTW BackgroundThread uses this class so it also good only for UI main
threads.

Other thoughts i am having are:
1)implementing message pump for the worker thread so it could receive
windows messages
2)Poll shared queue for incomming messages from the worker thread(i'd
hate to do that since i want the user to be free of that)


I will be more then happy to hear if u found any other solution since i
am frustrated about this situation.

Regards
Shay
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top