COM Visible library fails to access the UI thread?

Martin 21 Reputation points
2022-06-08T11:44:53.777+00:00

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?

Developer technologies | VB
{count} votes

2 answers

Sort by: Most helpful
  1. Albert Kallal 5,586 Reputation points
    2022-06-09T22:38:33.793+00:00

    Ok, unfortanly I don't have vb6 installed on my current pc. (first time in a VERY long time that I never go around to setup + install of Vb6).

    however, I do have ms-access, and VBA - and their event models should be simular.

    I find that from VBA, I can use a vb.net class, and if I launch forms from that VBA "com" object, the .net form(s) are able freely to launch. And the .net forms work fine - including display of msg box or whatever.

    However, I do no launch the .net form(s) as dialog, and you probably don't want to do that, since that would in theory "freeze" the vb6/vba UI from allowing call backs (if you have any).

    So, I can't say the above helps a whole lot, but as long as the calling code (VBA/VB6) does not wait, or get stuck in a dialog form (from .net), then you should be ok.

    In other words, don't launch/show/display the .net forms as dialog, and don't let the VB6 code "halt" when it launches the .net forms (such as waiting for a .net dialog and waiting to continue).

    However, I find that even when I launch the .net form as dialog, (and VBA code halts, waits), I find that the .net form and UI - and even use of msgbox (or other dialog forms) works just fine. And when I close the .net form, the calling VBA code can thus continue.

    I don't think the above behavior would change much in regards to the client being VB6.

    So, say I build this simple vb.net class

    Imports System.Runtime.InteropServices  
      
    <ClassInterface(ClassInterfaceType.AutoDual)>  
    Public Class Class1 : Implements IDisposable  
      
        Private disposedValue As Boolean  
        Dim f1 As New Form1  
      
      
        Public Sub HelloWorld()  
      
            MsgBox("Hello from .net!")  
      
        End Sub  
      
        Public Function MyMultiply(x As Double, y As Double) As Double  
      
            Return x * y  
      
        End Function  
      
      
        Sub ShowForm()  
      
            f1.Show()  
      
        End Sub  
      
        Sub CloseForm()  
      
            f1.Close()  
      
        End Sub  
      
        Sub ShowFormDialog()  
      
            f1.ShowDialog()  
      
        End Sub  
      
      
        Protected Overridable Sub Dispose(disposing As Boolean)  
            If Not disposedValue Then  
                If disposing Then  
                    ' TODO: dispose managed state (managed objects)  
                    f1.Close()  
                    f1.Dispose()  
      
                End If  
      
                ' TODO: free unmanaged resources (unmanaged objects) and override finalizer  
                ' TODO: set large fields to null  
                disposedValue = True  
            End If  
        End Sub  
      
        ' ' TODO: override finalizer only if 'Dispose(disposing As Boolean)' has code to free unmanaged resources  
        ' Protected Overrides Sub Finalize()  
        '     ' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method  
        '     Dispose(disposing:=False)  
        '     MyBase.Finalize()  
        ' End Sub  
      
        Public Sub Dispose() Implements IDisposable.Dispose  
            ' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method  
            Dispose(disposing:=True)  
            GC.SuppressFinalize(Me)  
        End Sub  
    End Class  
      
    

    Ok, force the project to x86 (this is a very good idea).

    Now, in vba/access, set a reference to the above object.

    This code (vba), works just fine.

    Private Sub Command0_Click()  
      
       Dim cls As New ComTest.Class1  
         
       cls.HelloWorld  
         
         
       cls.ShowFormDialog  
         
       MsgBox "wait"  
         
       cls.Dispose  
         
    End Sub  
      
    

    so, when I run, the first method (Hello world runs), and I see this in ms-access.

    210044-image.png

    And then ok, and then the next method (to display .net form as dialog) then shows.

    210007-image.png

    And all of the buttons, and UI on that form - even as dialog shows.

    And if I close form, then VBA code continues and we are done.

    Regards,
    Albert D. Kallal (Access MVP 2003-2017)
    Edmonton, Alberta Canada


  2. Martin 21 Reputation points
    2022-06-14T10:02:20.133+00:00

    I found that events mess up the internal message loop for VB6 so instead I tried using callbacks. With a callback class I can run methods on the same thread as they where started on and this resulted in a very good way to show .NET forms in VB6. It even works with .NET modal dialogs and they can open VB6 forms without the need of closing the .NET forms.

    The answer to using .NET forms and VB6 forms together is not to use events at all. Use callbacks. Just be careful with threading because callbacks that use VB6 UI only work if you run them from the thread on which VB6 started the .NET code.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.