Results 1 to 14 of 14

Thread: [RESOLVED] COM Visible library fails to access the UI thread?

  1. #1

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Resolved [RESOLVED] COM Visible library fails to access the UI thread?

    I'm building a COM visible library that should be used in VB6. I need to use WinForms in the library that can be used from within VB6 to open .NET Forms. This all currently works fine. The problem is when I trigger an event on the .NET Form that is being read by VB6. VB6 seems to be unable to perform any type of UI action while the .NET form is open. So handling an event and displaying a simple MsgBox does not work. The code runs but the MsgBox is never shown.

    I have the feeling that this has something to do with multithreading and not being able to run on the VB6 UI-thread. How do I know it's multithreading? Because when I set a breakpoint in the VB6 event handler it hits the breakpoint without pausing the actual application UI like it normally would when you use VB6 code only.

    After this problem I started testing with the Interop Form Toolkit because that should be able to make .NET Forms work from within VB6. It's true, the toolkit works as advertised but it fails with the same problem. Events handled from the .NET Form are still unable to open a MsgBox or any other VB6 form.

    Does anyone know if it is possible to keep using the VB6 UI elements while a .NET Form is opened?

  2. #2
    Fanatic Member
    Join Date
    Jun 2015
    Posts
    748

    Re: COM Visible library fails to access the UI thread?

    If they are in different threads try using ipc instead of a direct callback from .net to vb6
    I always use wm_copy data since itís synchronous.

    http://sandsprite.com/openSource.php?id=70

    It could also be that the .net ui is in the same thread but being shown modal thatís a different problem.
    Last edited by dz32; Jun 9th, 2022 at 11:10 AM.

  3. #3

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by dz32 View Post
    If they are in different threads try using ipc instead of a direct callback from .net to vb6
    I always use wm_copy data since itís synchronous.

    http://sandsprite.com/openSource.php?id=70

    It could also be that the .net ui is in the same thread but being shown modal thatís a different problem.
    Exchanging the data isn't the problem. I have events and callbacks working.

    The form being shown modal could be something. I checked both modal and non-modal and the non-modal seems to be working allot better although it still fails when the callback is being initiated from another thread. I will test this further with some invokes to the main thread.

    Is there a solution to the modal form problem? It is quite common to pop up another modal form from an existing modal form. But doing so from a .NET modal form breaks the chain since VB6 won't create a new form while the .NET modal form is open.

  4. #4
    Fanatic Member
    Join Date
    Jun 2015
    Posts
    748

    Re: COM Visible library fails to access the UI thread?

    The ipc was do an easy form of marshal and synchronization across threads.
    You receive the data and events fine but the ipc test would resolve any threading issues.

  5. #5
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    7,803

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by 3raser View Post
    So handling an event and displaying a simple MsgBox does not work. The code runs but the MsgBox is never shown.
    You're going to have to provide a very clear picture of what you're talking about here. In this case, every detail matters.

    What event? Where is the event being raised? Where is it being handled? Is the event being raised in .Net or VB6? Is it being handled in .Net or VB6? Are you using worker threads on the .Net side?
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  6. #6

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by Niya View Post
    You're going to have to provide a very clear picture of what you're talking about here. In this case, every detail matters.

    What event? Where is the event being raised? Where is it being handled? Is the event being raised in .Net or VB6? Is it being handled in .Net or VB6? Are you using worker threads on the .Net side?
    Let's start with a little piece of .NET code. This is the code I have been using for testing .NET events with. As you can see this code is COM exposed so that VB6 can use the class. The Form itself is not exposed but is being opened by calling the ShowModal or ShowNonModal methods. The Form opens and shows a button. When you click that button the frmTest.Testing event is being raised which in turn raises the FormTest.Testing event.
    Code:
    Imports System.Runtime.InteropServices
    
    ' This interface is to expose the events
    <ComVisible(True), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
    Public Interface FormTestEvents
        <DispId(1)>
        Sub Testing()
    End Interface
    
    <ComVisible(True),
        ClassInterface(ClassInterfaceType.AutoDual),
        ComSourceInterfaces(GetType(EventTestEvents))>
    Public Class FormTest
    
        Private WithEvents _Form As New frmTest
    
        Public Event Testing()
    
        Public Sub ShowNonModal()
            _Form.Show()
        End Sub
    
        Public Sub ShowModal()
            _Form.ShowDialog()
        End Sub
    
        Private Sub _Form_Testing() Handles _Form.Testing
            RaiseEvent Testing()
        End Sub
    
    End Class
    Within VB6 I create a standard Form with a button. The Form code looks like this:
    Code:
    Option Explicit
    
    Private WithEvents FormTest As FormTest
    
    Private Sub Command1_Click()
        Set FormTest = New FormTest
        'FormTest.ShowNonModal
        FormTest.ShowModal
    End Sub
    
    Private Sub FormTest_Testing()
        Debug.Print "FormTest_Testing"
        MsgBox "FormTest Testing event"
        frmTest.Show 1
    End Sub
    When the Command1 button is clicked the FormTest class is initialized and FormTest.ShowModal is being run. Right now the VB6 application shows the .NET Form. Untill this point there are no problems. After that, I click on the button from the .NET Form which raises the Testing event. This Testing event should be handled by VB6 in the FormTest_Testing method, but unfortunately it's not. My guess is that VB6 stopped executing code because .NET is showing the modal form.

    If I change the VB6 code so that FormTest.ShowNonModal is being run instead of FormTest.ShowModal then the same test results in the FormTest_Testing being run and even the VB6 frmTest form is being shown. So VB6 did not stop executing code. This is because I used a NonModal form.

    There is another way to let VB6 know that an action is required from within the .NET code. That is when you use a callback class. It requires some extra code but the result is that when you click the .NET button the action is being run instantly on the same thread as where the button was clicked. This is usefull because that code is not blocked when a modal form is being shown. The problem is that you cannot open new VB6 forms on that thread. It results in a VB6 error: Invalid procedure call or argument

    That is where my question comes in. How to have a modal form in a .NET library that can open a VB6 modal form?

  7. #7
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    7,803

    Re: COM Visible library fails to access the UI thread?

    Can you tell me the ApartmentState of the thread that is executing that .Net code? You could add a method to the .Net class that reports this to the VB6 side. You can get the apartment state of the current thread like this:-
    Code:
        Private Function GetApartmentState() As String
            Return Threading.Thread.CurrentThread.GetApartmentState().ToString
        End Function
    It should be STA. One other thing, I don't see the code that raises the Testing event of frmTest.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  8. #8
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    33,923

    Re: COM Visible library fails to access the UI thread?

    I'm questioning whether modal forms can even raise events to be handled externally... in that case this event handler:
    Code:
        Private Sub _Form_Testing() Handles _Form.Testing
            RaiseEvent Testing()
        End Sub
    Never gets raised.
    Have you tried putting a breakpoint on that RaiseEvent to see if it's even getting in to it?

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  9. #9
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    7,803

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by techgnome View Post
    I'm questioning whether modal forms can even raise events to be handled externally... in that case this event handler:
    Code:
        Private Sub _Form_Testing() Handles _Form.Testing
            RaiseEvent Testing()
        End Sub
    Never gets raised.
    Have you tried putting a breakpoint on that RaiseEvent to see if it's even getting in to it?

    -tg
    Yes they can. I tested it:-
    Code:
    Public Class Form1
    
        Private WithEvents _f As Form
    
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
            _f = New Form
    
            _f.ShowDialog()
        End Sub
    
        Private Sub FormMove(ByVal sender As Object, ByVal e As EventArgs) Handles _f.Move
            Debug.WriteLine("Moving")
        End Sub
    
    End Class
    I'm guessing the reason they aren't working on the VB6 side has to do with how the COM wrappers work. COM under many circumstances require a message loop for object methods to be called. It's a way of synchronizing method calls that come from other threads. That's why I asked about the apartment state of the thread his .Net methods are running on so I can at least know how to think about what may be happening. ShowDialog creates it's own message loop which prevents VB6's message loop from running. If COM is using the VB6 message loop to call the methods on the CCW, this it would explain why his event is not raising. I can't be certain of this though. I will have to do my own testing.
    Last edited by Niya; Jun 10th, 2022 at 09:16 AM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  10. #10

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by Niya View Post
    Can you tell me the ApartmentState of the thread that is executing that .Net code? You could add a method to the .Net class that reports this to the VB6 side. You can get the apartment state of the current thread like this:-
    Code:
        Private Function GetApartmentState() As String
            Return Threading.Thread.CurrentThread.GetApartmentState().ToString
        End Function
    It should be STA. One other thing, I don't see the code that raises the Testing event of frmTest.
    It says STA.

    And I thought the code for frmTest would be to obvious to post. But here it is:
    Code:
    Public Class frmTest
    
        Event Testing()
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            RaiseEvent Testing()
        End Sub
    End Class

  11. #11

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by techgnome View Post
    I'm questioning whether modal forms can even raise events to be handled externally... in that case this event handler:
    Code:
        Private Sub _Form_Testing() Handles _Form.Testing
            RaiseEvent Testing()
        End Sub
    Never gets raised.
    Have you tried putting a breakpoint on that RaiseEvent to see if it's even getting in to it?

    -tg
    It's not possible for me to set breakpoints on .NET code while running it from the VB6 IDE. But when I test this within .NET itself it works. It also works when I raise the event on the form and then raise it again from the class that opened the form.

    But in case an event would really fail to work in VB6 then a Callback can be implemented. Breakpoints within VB6 show that these callbacks work.

  12. #12

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by Niya View Post
    I'm guessing the reason they aren't working on the VB6 side has to do with how the COM wrappers work. COM under many circumstances require a message loop for object methods to be called. It's a way of synchronizing method calls that come from other threads. That's why I asked about the apartment state of the thread his .Net methods are running on so I can at least know how to think about what may be happening. ShowDialog creates it's own message loop which prevents VB6's message loop from running. If COM is using the VB6 message loop to call the methods on the CCW, this it would explain why his event is not raising. I can't be certain of this though. I will have to do my own testing.
    That is indeed where my quest has taken me thus far. I also think the message loop in VB6 stops so events will never get hit. That's why I tried it with a callback method because that is being initiated by the caller. Breakpoints in VB6 show that the callbacks work. But it fails to open VB6 forms. Maybe due to the message loop that is paused. The question is how to get around this problem. I can barely imagine that nobody has had this problem before but I can't find a solution thus far. Opening the form as non-modal could work but that's not really a solution when you require a modal form. You also have to be careful with non-model forms because when the VB6 application closes these windows stay open. It's like they don't get the call that the application closes. But that's a problem for another thread.

  13. #13

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    For reference, this is the code for testing a callback.

    .NET interface that defines the callback class.
    Code:
    Imports System.Runtime.InteropServices
    
    <ComVisible(True),
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
    Public Interface IControlCallback
    
        Sub TestCallback()
    
    End Interface
    .NET class for testing the callback. This uses the same frmTest form as before.
    Code:
    Imports System.Runtime.InteropServices
    
    <ComVisible(True),
        ClassInterface(ClassInterfaceType.AutoDual)>
    Public Class TestCallback
    
        Private WithEvents _Form As New frmTest
        ReadOnly Property Callback As IFromCallback
    
        Public Sub SetCallback(Callback As IFromCallback)
            _Callback = Callback
        End Sub
    
        Public Sub ShowNonModal()
            _Form.Show()
        End Sub
    
        Public Sub ShowModal()
            _Form.ShowDialog()
        End Sub
    
        Private Sub _Form_Testing() Handles _Form.Testing
            If Callback IsNot Nothing Then
                Callback.TestCallback()
            End If
        End Sub
    
    End Class
    In VB6 I created a callback class for handling the code that should run when clicking the .NET form button.
    Code:
    Option Explicit
    Implements IFormCallback
    
    Private Sub IFormCallback_TestCallback()
        Debug.Print "Callback hit!"
        MsgBox "Testing msgbox through callback"
        'Now open a modal form through the callback.
        frmTest.Show 1
    End Sub
    Now in VB6 create the code for running the .NET class with a reference to the VB6 callback class.
    Code:
    Private Sub Command1_Click()
        Dim Callback As New FormCallback
        Dim TestNetCallback As New TestCallback
        TestNetCallback.SetCallback Callback
        TestNetCallback.ShowModal
    End Sub
    And to my surprise, this now works! I will test this more thoroughly to see what I missed last time.

  14. #14

    Thread Starter
    New Member
    Join Date
    Mar 2011
    Posts
    11

    Re: COM Visible library fails to access the UI thread?

    Quote Originally Posted by 3raser View Post
    I will test this more thoroughly to see what I missed last time.
    I think last time I tested this I was more demanding. I tested the same callback method in different threads and in a backgroundworker. That clearly doesn't work because from within VB6 it runs this as if the modal form was non-modal.

    So I think the answer to my own question "Does anyone know if it is possible to keep using the VB6 UI elements while a .NET Form is opened?" is: By using a callback class that works on the same thread as the one that opened the .NET code.

    If there is anyone with a better answer, like how to make events work from a modal form, then I still love to hear them.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width