-
Jun 9th, 2022, 02:57 AM
#1
Thread Starter
New Member
[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?
-
Jun 9th, 2022, 08:46 AM
#2
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.
-
Jun 9th, 2022, 01:31 PM
#3
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by dz32
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.
-
Jun 9th, 2022, 02:34 PM
#4
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.
-
Jun 9th, 2022, 05:50 PM
#5
Re: COM Visible library fails to access the UI thread?
Originally Posted by 3raser
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?
-
Jun 10th, 2022, 07:08 AM
#6
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by Niya
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?
-
Jun 10th, 2022, 08:56 AM
#7
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.
-
Jun 10th, 2022, 09:04 AM
#8
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
-
Jun 10th, 2022, 09:13 AM
#9
Re: COM Visible library fails to access the UI thread?
Originally Posted by techgnome
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.
-
Jun 13th, 2022, 01:59 AM
#10
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by Niya
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
-
Jun 13th, 2022, 02:17 AM
#11
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by techgnome
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.
-
Jun 13th, 2022, 02:35 AM
#12
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by Niya
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.
-
Jun 13th, 2022, 02:53 AM
#13
Thread Starter
New Member
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.
-
Jun 13th, 2022, 03:09 AM
#14
Thread Starter
New Member
Re: COM Visible library fails to access the UI thread?
Originally Posted by 3raser
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|