Multithreading and Event Marshalling Question Using The Tricks Threading example
Originally Posted by The trick
Private events won't work, because they require marshaling.
Hello Trick,
Did not understand.
1. Can you show how to make private objects/events work using marshalling using Marshal/Marshal2 and UnMarshal functions along with CreatePrivateObjectByNameInNewThread.
2. Can the above be extended for public objects(activex objects)/events using CreateActiveXObjectInNewThread2.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
1. Can you show how to make private objects/events work using marshalling using Marshal/Marshal2 and UnMarshal functions along with CreatePrivateObjectByNameInNewThread.
Private objects don't support events because events require marshaling. You can use another solution to notify the main thread (see examples).
2. Can the above be extended for public objects(activex objects)/events using CreateActiveXObjectInNewThread2.
Public events are supported. You can declare variable as usual.
Re: [VB6] - Module for working with multithreading.
smkperu i see you don't understand what is marshaling is for. You can't share a COM (STA) object reference without marshaling. When you declare a variable with a private interface there is no information how to transfer the parameters from one apartment to another one. When you declare a variable with a public interface it uses description from a typelibrary. There is no typelibrary for private interfaces/classes in VB.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
smkperu i see you don't understand what is marshaling is for. You can't share a COM (STA) object reference without marshaling. When you declare a variable with a private interface there is no information how to transfer the parameters from one apartment to another one. When you declare a variable with a public interface it uses description from a typelibrary. There is no typelibrary for private interfaces/classes in VB.
Hello Trick,
When we declare a private user object in one thread in standard exe project if we want to call its methods to be called from another thread
we use Marshal/Marshal2 to marshal it to the other thread and we obtain unmarshaled object in new thread using unmarshal.
So when we are using marshalling for private objects manually why not we use marshalling for private user events also manually.Can you show using a simple example for my understanding.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
When we declare a private user object in one thread in standard exe project if we want to call its methods to be called from another thread
we use Marshal/Marshal2 to marshal it to the other thread and we obtain unmarshaled object in new thread using unmarshal.
So when we are using marshalling for private objects manually why not we use marshalling for private user events also manually.Can you show using a simple example for my understanding.
Thanks
We never get an unmarshaled object but we get unmarshaled interface reference (pointer). I never use private interfaces in my examples. If you noted i use Object (or another public interface) type which is public IDispatch interface alias.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
We never get an unmarshaled object but we get unmarshaled interface reference (pointer). I never use private interfaces in my examples. If you noted i use Object (or another public interface) type which is public IDispatch interface alias.
Hello Trick,
I achieved using receiving events in standard exe
using the following code in Form1 :
Code:
Public WithEvents m_class1 As Class1
Private Sub Command1_Click()
Dim thid As Long
Set lfrm1 = Me
vbCreateThread 0, 0, AddressOf th1, 0, 0, thid
End Sub
Private Sub Form_Load()
modMultiThreading.Initialize
Me.Caption = App.ThreadID
End Sub
Private Sub Form_Unload(Cancel As Integer)
modMultiThreading.Uninitialize
End Sub
Private Sub m_class1_abc()
MsgBox "in abc evt threadid= " & App.ThreadID
End Sub
where th1 is defined in modMultiThreading2 as follows:
' // Private object thread
Public Function th1( _
ByVal data As Long) As Long
Dim lclass1 As Object
Set lclass1 = New Class1
Set lfrm1.m_class1 = lclass1
lclass1.memfunc
End Function
I defined lfrm1 As global in module as follows:
Public lfrm1 As Object
and initialized in Command_Click() as follows:
Set lfrm1 = Me
and used it to get m_class1 in thread th1 as follows:
Set lfrm1.m_class1 = lclass1
Is this the correct way or is there any other method
of getting main thread form1 object.
Thanks
Last edited by smkperu; Sep 11th, 2023 at 07:44 AM.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
By using WithEvents statement.
Hello Trick,
Events are received in the same thread in which the source object is called which always requires extra thread on the client side so as to keep the main thread always responsive.
But this not the case with callbacks where this extra thread is not required since callbacks from arbitrary threads of component run directly in client independent of main thread.
How to overcome this overhead of extra thread when using events on client side using withevents.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
Events are received in the same thread in which the source object is called which always requires extra thread on the client side so as to keep the main thread always responsive.
But this not the case with callbacks where this extra thread is not required since callbacks from arbitrary threads of component run directly in client independent of main thread.
How to overcome this overhead of extra thread when using events on client side using withevents.
Thanks
Read about marshaling. When a COM object fires an event it transmits the call to all the apartments subscribed.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
Read about marshaling. When a COM object fires an event it transmits the call to all the apartments subscribed.
Hello Trick,
Visual Basic uses apartment threading model. Cross-thread function calls need
to be marshalled. Visual Basic does not support events fired directly from any
thread other than the main thread created by a Visual Basic project without
marshalling.
In order Fire Event in Secondary thread we have to
Marshal the event firing code:
1. The thread being spun off needs to call CoInitialize/CoUnInitialize.
2. The sink interface being called back on in the thread must be marshalled over
to that thread with CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream.
This shows that even though the event is fired in Secondary thread of public object
or component thru sink interface it is received in the same thread from which the source object was called at the client side.
But this is not the case with callbacks and the callback is called in new thread directly because no marshalling is required.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
Visual Basic uses apartment threading model. Cross-thread function calls need
to be marshalled. Visual Basic does not support events fired directly from any
thread other than the main thread created by a Visual Basic project without
marshalling.
In order Fire Event in Secondary thread we have to
Marshal the event firing code:
1. The thread being spun off needs to call CoInitialize/CoUnInitialize.
2. The sink interface being called back on in the thread must be marshalled over
to that thread with CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream.
This shows that even though the event is fired in Secondary thread of public object
or component thru sink interface it is received in the same thread from which the source object was called at the client side.
But this is not the case with callbacks and the callback is called in new thread directly because no marshalling is required.
Thanks
This is the COM rules. If you need to use raw callbacks you should use InitCurrentThreadAndCallFunction.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
This is the COM rules. If you need to use raw callbacks you should use InitCurrentThreadAndCallFunction.
Hello Trick,
I mentioned about the same raw callbacks as callbacks in the callback demo provided.
How to fire event from a secondary thread using sink interface so that it can behave just like
this raw callbacks ie., the event should be able to be received in the same secondary thread.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
I mentioned about the same raw callbacks as callbacks in the callback demo provided.
How to fire event from a secondary thread using sink interface so that it can behave just like
this raw callbacks ie., the event should be able to be received in the same secondary thread.
Thanks
COM events should follow COM rules. VB thread is STA thread so it can only process the events in the subscriber STA.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
COM events should follow COM rules. VB thread is STA thread so it can only process the events in the subscriber STA.
Hello Trick,
This is the reason I mentioned that we have to create another(extra) VB thread on client side so that events can be processed or received in this subscriber thread without disturbing
the default main VB thread.
Re: [VB6] - Module for working with multithreading.
Hello Trick,
If I use a public object in (activex dll) with atleast one event and use it in my standard exe supporting MultiThreading( using your modMultiThreading2.bas) by adding thru project references,
what is the difference I get when the activex dll is having Threading model set to
1.single threaded
2.apartment threaded.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
If I use a public object in (activex dll) with atleast one event and use it in my standard exe supporting MultiThreading( using your modMultiThreading2.bas) by adding thru project references,
what is the difference I get when the activex dll is having Threading model set to
1.single threaded
2.apartment threaded.
Can you provide a simple example.
Thanks
1 - all the instances should live in the main STA thread;
2 - all the instances can live in the different STA threads.
Re: [VB6] - Module for working with multithreading.
Hello Trick,
1. In a std exe
when we create and display a private object in new thread it is created in new thread.
But even when we create and display a public object in new thread it is created in main thread which can be verified by displaying app.ThreadId if the public object threading model is single threaded.
Why is this difference between a private object in a standard exe and public object(single threaded) used in the same standard exe even though we are displaying in new thread using vbCreateThread.
What is the threading model of standard exe for this private object .Projects (public object and std exe) attached.
2. In a activex dll with single threaded
when we create a new thread and display a std exe private object it is displayed in new thread successfully.
But in a activex dll with apartment threaded
when we create a new thread and display a std exe private object it fails.How to make the private object creation successful.
Thanks
Last edited by smkperu; Sep 26th, 2023 at 06:28 AM.
Re: [VB6] - Module for working with multithreading.
If an ActiveX DLL has the single threading model it works as it should (because it's the COM rules). If each object in single thread model will live in its own thread it won't work because library doesn't expect such behavior (for example there is no global variable isolation).
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
If an ActiveX DLL has the single threading model it works as it should (because it's the COM rules). If each object in single thread model will live in its own thread it won't work because library doesn't expect such behavior (for example there is no global variable isolation).
Hello Trick,
When we create a thread in std exe it works when we use vbCreateThread without any restrictions.
But when we create thread in public object actx dll(single threaded) and try to run it in std exe
it crashes. How to make this to work successfully without crash in the actx dll(single threaded) just like vbCreateThread in std exe.
Projects(stdexe and actx dll(single threaded)) simpleactsingledemo attached
Thanks
Last edited by smkperu; Sep 27th, 2023 at 01:28 AM.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
I don't understand you and didn't see my module in your project.
Hello Trick,
This is similar to your callback demo.
Only difference is you are using standard dll(CallbackDll.dll) and I am using (activex dll single threaded)simpleactsingle.dll.
You are using CreateThread api in CallbackDll project as I do in simpleactsingle.dll.
But here there is a difference.I am trying to use my activex dll private objects or MsgBox for example to be shown in thread using thread initialization thru multi use class object creation using CreateObject in the thread in dll.
You have not created any private objects like forms or MsgBox in new thread of CallbackDll standard dll project.You are only showing how to use resources of standard exe thru its callback in the thread to which CallbackDll.dll is loaded.
Now coming to (activex dll singlethreaded)simpleactsingle.dll.If I set the project to apartment threaded
and run the std exe I get my form or msgbox of actx dll displayed in thread without having to usevbCreateThread or your modulesuccessfully without crash.
But since the same simpleactsingle.dll is crashing when set to single threaded I was asking can I avoid this crash and make the demo run successfully by using module(vbheader solution in exe or dll) in the project so that I can show MsgBox or private objects of my activex dll (single threaded) in the dll thread thru std exe.
Re: [VB6] - Module for working with multithreading.
What is a multithreaded solution that can run stably under the VB6 IDE without crashing? No need to debug, just run once, stop, then F5, repeat many times running without crashing.
Re: [VB6] - Module for working with multithreading.
Originally Posted by xiaoyao
What is a multithreaded solution that can run stably under the VB6 IDE without crashing? No need to debug, just run once, stop, then F5, repeat many times running without crashing.
This module runs the code in the main thread when you debug in IDE.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
This module runs the code in the main thread when you debug in IDE.
Hello Trick,
When we run the code with actx dll set to single threaded the code in the dll thread runs in main thread even when run compiled outside IDE according to COM rules as you already explained.
The code in the Dll thread runs in the same new thread when set to Apartment threaded model when run compiled.
There are two options:
Either
1. Change the threading model to Apartment Threaded dynamically at runtime before starting the thread so that it runs as Apartenet threaded and after thread completion reset it to single threaded.
or
2. initialize the Dll thread properly either thru vbheader or creating multiuse classso that the code in the thread runs in main thread without crashing when the dll thread is set to single threaded model.
Re: [VB6] - Module for working with multithreading.
Originally Posted by Cube8
You can have multiple processes, but this topic is about having a single exe.
I mean there is no way to debug multithreading in the VB6 IDE.If we open three VB6 processes to simulate multithreading and then debug. It's more fun this way. One of them is used as the main process UI to display the running progress.
Re: [VB6] - Module for working with multithreading.
Has anyone learned how to debug VB6 multithreading? If you open a main program, three child processes. () Write a plug-in addin, a total of 4 VB6 processes, can turn three child processes into tabs, can run at the same time pause the end.
In fact, it is good to copy the project into multiple projects and open them at the same time when needed.The main technical difficulty is the common variable.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
When we create a thread in std exe it works when we use vbCreateThread without any restrictions.
But when we create thread in public object actx dll(single threaded) and try to run it in std exe
it crashes. How to make this to work successfully without crash in the actx dll(single threaded) just like vbCreateThread in std exe.
Projects(stdexe and actx dll(single threaded)) simpleactsingledemo attached
Thanks
Hello Trick,
I made a activex dll (single threaded) actxdllwithapt_threaded1.dll with a form, module and multiuse class as follows:
Class1 (multiuse class) code
Code:
Option Explicit
Dim lThreadId As Long
Dim hThread As Long
Public Sub CreateFormofdllinNewThread()
Dim tThData As tThreadData
hThread = CreateThread(ByVal 0&, 0, AddressOf ThreadProc, tThData, 0, lThreadId)
End Sub
Public Sub CloseThread()
If lThreadId = 0 Then Exit Sub
CloseHandle hThread
lThreadId = 0
End Sub
Private Sub Class_Terminate()
CloseThread
End Sub
modMain.bas module code
Code:
Option Explicit
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Const CC_STDCALL As Long = 4
Public Const WM_EXITTHREAD As Long = &H8001&
' // Lazy GUID structure
Public Type tCurGUID
c1 As Currency
c2 As Currency
End Type
Public Type tThreadData
pStream As Long
hEvent As Long
End Type
Public Type POINTAPI
x As Long
y As Long
End Type
Public Type MSG
hwnd As Long
message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
''''''''''''''''''''''''''''''''''''''''''
'Option Explicit
'Private Const CC_STDCALL As Long = 4
Private Declare Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryW" ( _
ByVal lpLibFileName As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" ( _
ByVal hModule As Long, _
ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" ( _
ByVal hLibModule As Long) As Long
Private Declare Function GetMem4 Lib "msvbvm60" ( _
ByRef pSrc As Any, _
ByRef pDst As Any) As Long
Private Declare Function lstrcmpA Lib "kernel32" ( _
ByRef lpString1 As Any, _
ByRef lpString2 As Any) As Long
Private Declare Function memcpy Lib "kernel32" _
Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long) As Long
Private m_cFactory As IUnknown
Private m_cContext As Object
Private m_hLibrary As Long
''''''''''''''''''''''''''''''''''''''''''
Public Declare Function GetModuleHandle Lib "kernel32" _
Alias "GetModuleHandleW" ( _
ByVal lpModuleName As Long) As Long
Public Declare Function CreateIExprSrvObj Lib "MSVBVM60.DLL" ( _
ByVal pUnk1 As Long, _
ByVal lUnk2 As Long, _
ByVal pUnk3 As Long) As IUnknown
Public Declare Function PostThreadMessage Lib "user32" _
Alias "PostThreadMessageW" ( _
ByVal idThread As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public Declare Function PostQuitMessage Lib "user32" ( _
ByVal nExitCode As Long) As Long
Public Declare Function GetMessage Lib "user32" _
Alias "GetMessageW" ( _
ByRef lpMsg As Any, _
ByVal hwnd As Long, _
ByVal wMsgFilterMin As Long, _
ByVal wMsgFilterMax As Long) As Long
Public Declare Function TranslateMessage Lib "user32" ( _
ByRef lpMsg As Any) As Long
Public Declare Function DispatchMessage Lib "user32" _
Alias "DispatchMessageW" ( _
ByRef lpMsg As Any) As Long
Public Declare Function CoInitialize Lib "ole32" ( _
ByRef pvReserved As Any) As Long
Public Declare Function CreateThread Lib "kernel32" ( _
ByRef lpThreadAttributes As Any, _
ByVal dwStackSize As Long, _
ByVal lpStartAddress As Long, _
ByRef lpParameter As Any, _
ByVal dwCreationFlags As Long, _
ByRef lpThreadId As Long) As Long
Public Declare Function CoMarshalInterThreadInterfaceInStream Lib "ole32.dll" ( _
ByRef riid As Any, _
ByVal pUnk As Any, _
ByRef ppstm As Any) As Long
Public Declare Function CoGetInterfaceAndReleaseStream Lib "ole32.dll" ( _
ByVal pstm As Long, _
ByRef riid As Any, _
ByRef pUnk As Any) As Long
Public Declare Function CreateStreamOnHGlobal Lib "ole32" ( _
ByVal hGlobal As Long, _
ByVal fDeleteOnRelease As Long, _
ByRef ppstm As Any) As Long
Public Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" ( _
ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long
Public Declare Function CreateEvent Lib "kernel32" _
Alias "CreateEventW" ( _
ByRef lpEventAttributes As Any, _
ByVal bManualReset As Long, _
ByVal bInitialState As Long, _
ByVal lpName As Long) As Long
Public Declare Function SetEvent Lib "kernel32" ( _
ByVal hEvent As Long) As Long
Public Declare Function DestroyWindow Lib "user32" ( _
ByVal hwnd As Long) As Long
Public Declare Sub CoUninitialize Lib "ole32" ()
Public Declare Function DispCallFunc Lib "oleaut32.dll" ( _
ByRef pvInstance As Any, _
ByVal oVft As Long, _
ByVal cc As Long, _
ByVal vtReturn As VbVarType, _
ByVal cActuals As Long, _
ByRef prgvt As Any, _
ByRef prgpvarg As Any, _
ByRef pvargResult As Variant) As Long
Public Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Public Declare Function VirtualProtect Lib "kernel32" ( _
ByVal lpAddress As Long, _
ByVal dwSize As Long, _
ByVal flNewProtect As Long, _
ByRef lpflOldProtect As Long) As Long
Public Declare Function VBDllGetClassObject Lib "MSVBVM60.DLL" ( _
ByRef phModule As Long, _
ByVal lReserved As Long, _
ByVal pVBHeader As Long, _
ByRef pClsid As Any, _
ByRef pIID As Any, _
ByRef pObject As Any) As Long
' // Modify VBHeader to replace Sub Main
Public Sub ModifyVBHeader(mpVbHeader As Long)
Dim ptr As Long
Dim lOldProtect As Long
Dim lFlags As Long
Dim lFormsCount As Long
Dim lModulesCount As Long
Dim lStructSize As Long
' // Allow to write to that page
VirtualProtect ByVal mpVbHeader, &H64, PAGE_EXECUTE_READWRITE, lOldProtect
' // Remove Sub Main
ptr = mpVbHeader + &H2C
GetMem4 0&, ByVal ptr ' 'AddressOf mymain
VirtualProtect ByVal mpVbHeader, &H64, lOldProtect, 0
End Sub
Public Function InitVbProjContext1() As IUnknown
Dim pVBHeader As Long
Dim pNewHeader As Long
Dim pCOMData As Long
Dim lOfstRegInfo As Long
Dim pRegInfo As Long
Dim pfn As Long
Dim hLib As Long
Dim iTypes(2) As Integer
Dim vParams(2) As Variant
Dim lList(2) As Long
Dim bIID(1) As Currency
Dim cFactory As IUnknown
Dim cObject As IUnknown
Dim hr As Long
Dim vRet As Variant
Dim tIID As tCurGUID
Dim tClsId As tCurGUID
hLib = GetModuleHandle(StrPtr("actxdllwithapt_threaded1.dll"))
MessageBox 0, "aft GetModuleHandle hLib= " & hLib, 0, 0
pfn = GetProcAddress(hLib, "DllGetClassObject")
MessageBox 0, "aft GetProcAddress pfn= " & pfn, 0, 0
If pfn = 0 Then Exit Function
tIID.c1 = 0.0001@
tIID.c2 = 504403158265495.5712@
' // Get VBHeader
GetMem4 ByVal pfn + 2, pVBHeader
MessageBox 0, "aft GetMem4 pVBHeader= " & pVBHeader, 0, 0
ModifyVBHeader pVBHeader
If pVBHeader Then
VBDllGetClassObject hLib, 0, pVBHeader, tClsId, tIID, 0
' MsgBox "VBDllGetClassObject"
MessageBox 0, "aft VBDllGetClassObject pVBHeader= " & pVBHeader, 0, 0
End If
End Function
Public Function ThreadProc( _
ByRef tData As tThreadData) As Long
Dim cExprSrv As IUnknown
Dim cInitObj As IUnknown
Dim cForm As Form1
Set cExprSrv = CreateIExprSrvObj(0, 4, 0)
CoInitialize ByVal 0&
Set cInitObj = InitVbProjContext1()
Set cForm = New Form1
cForm.Show vbModal
Set cForm = Nothing
Set cInitObj = Nothing
CoUninitialize
End Function
When I add athe actx dll (actxdllwithapt_threaded1.dll) thru proj references and call CreateFormofdllinNewThread of Class1 object as follows to std exe (Project1.exe):
Code:
Dim x As actxdllwithapt_threaded1.Class1
Private Sub Command1_Click()
Set x = New actxdllwithapt_threaded1.Class1
x.CreateFormofdllinNewThread
End Sub
the std exe crashes when clicked on Command1_Click button.How to make prevent this crash and run the std exe successfully.
std exe (Project1 ) and actx(single threaded) actxdllwithapt_threaded1 projects attached in the same folder.
Thanks
Last edited by smkperu; Oct 4th, 2023 at 10:21 AM.