Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes. This is common issue in Windows Forms applications, and for that matter in native Windows applications (e.g. those written in C/C++ against the native Windows API). You have different pieces here, but it's the same problem.</p> <p>Let me give you some background:</p> <p>First, you need to know that .NET Events are nothing but a convenient wrap around delegates, intended to make it easy to define methods in your class which "<strong><em>others</em> will implement, and <em>your class</em> will call</strong>". Note the difference between that and 'normal' methods, which are those "<em>your class</em> implements and <em>others</em> will call". The key observation is that <em>Events don't know anything about threading</em>.</p> <p>If you think about it, you will realize that that is also true of VB6 events.</p> <p>The second thing you need to know is that Windows controls, which is what VB6 uses, as well as controls in .NET's Windows.Forms world (and WPF for that matter) are bound by what's called <em>thread affinity</em>: they can ONLY be accessed from the thread that created them.</p> <p>Note that Forms (both Windows/VB6 and .NET Forms) are controls themselves (albeit very complicated ones) so this is all true for Forms.</p> <p>Put the two facts together... and you will immediately see what's going on. When your working thread code raises the event, it's just calling the event listener method directly, and it does so from the <em>wrong</em> thread. The moment the event listener method in VB6 (running from the working thread instead of the VB6 main thread) touches any Windows control in your VB6 form, "<em>puff</em>".</p> <p>In the .NET Windows.Forms world, Microsoft did all the really hard work for you.</p> <p>Every Control object (including the Form object) comes with a method called <code>Invoke()</code>. If a working thread has to communicate something to a form/control, it does not manipulate the controls directly. Instead, the form that hosts the control must implement an appropriate delegate, and the working thread calls the form's <code>Invoke()</code> method with that delegate as an argument and possibly some data parameters. <code>Control.Invoke()</code> then takes care of all the threading messiness and makes sure the delegate is called from the thread that created the form and its controls. Finally, the delegate method implemented by the form takes care of manipulating the form's controls on behalf of the working thread.</p> <p>Calling the delegate method directly from a working thread instead of using the <code>Control.Invoke()</code> method is a sure-fire way of crashing the application.</p> <p>Now, I confess: my immediate reaction when I read your question was "Yeah, I know exactly what's going on; I'll just explain..." and then I realized that I only had a faint idea of how the .NET framework actually handles this internally. And then I thought some more, and realized that this was not a simple task at all.</p> <p>No problem! I just loaded <code>System.Windows.Forms.DLL</code> in <em>Reflector</em> to quickly check out the implementation of <code>Control.Invoke()</code>... and felt all the blood drained out of my face. There is some serious <em>ninjitzu</em> going on in there. Go ahead and take a look for yourself.</p> <p>When you are done, you will understand the <em>why</em> of Hans's suggestion -- and that is my suggestion as well:</p> <p><em>Create a hidden .NET Form. Make sure you <code>new</code> the form from the thread used by VB6. Use the methodology I described above and have the working thread call a delegate in the hidden form via <code>Invoke()</code>. Then the delegate can raise your Event. Everyhing will then work correctly.</em></p> <p>I know. It sounds crazy overkill to create a hidden window just to change the thread used to call a function; but it's not. You should know that that's <em>exactly</em> how COM handles communications between VB6-style COM objects (called STA objects) and multi-threaded COM objects.</p> <p>Whether or not the extra benefit is worth the hassle, only you can decide.</p> <p>Good Luck.</p> <p><em>References:</em> </p> <ul> <li>The <a href="http://msdn.microsoft.com/en-us/library/a1hetckb.aspx" rel="nofollow">MSDN topic</a> for <code>Control.Invoke()</code> has an example in VB.NET that can be quickly distilled down to what you need. Add a comment to this response if you have difficulties parsing the example and I'll try to help.</li> </ul>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload