dcsimg
Page 1 of 2 12 LastLast
Results 1 to 40 of 61

Thread: [ADVANCED] Multi-threaded VB6

  1. #1

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    [ADVANCED] Multi-threaded VB6

    Yes, it does exist. VB6 supports native multi-threading (proof)

    I am trying to communicate between threads, but if thread A is busy and thread B tries to update thread A, thread B gets locked up until thread A finishes. I've tried using timers, custom events, nothing allows me to change memory on another thread without yielding (DoEvents).

    Does anyone know how to do this?

    The only thing I can think of is making a third thread that relays messages between thread A and B and doesn't do any processing to lock up thread A or B. However there should be some way to serialize/queue requests to other threads and continue. VB is doing this automatically when threads are busy.

    Thanks,
    PsuFan

  2. #2
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    1,973

    Re: [ADVANCED] Multi-threaded VB6

    LOL... and you call that "native" support?

    EDIT: btw: I'm surprised that you didn't think of the obvious solution to try: Global variables.....
    Last edited by Zvoni; May 9th, 2019 at 03:14 AM.
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  3. #3

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    Well I guess it could be a little more native. I wish you could use global variables, however global variables are NOT common between threads. VB calls Sub Main again so that you can reload global variables, they do not use the same memory locations. They do this for performance due to cross thread marshaling.

  4. #4
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    1,973

    Re: [ADVANCED] Multi-threaded VB6

    OK. That article describes also, that you can pass the MainApp-Object (for the MainThread) as a Reference to any new ChildThread.
    Why not just use a Public Property of MainApp?

    MainApp has a Public Property called "CrossThread As Long" (Or whatever you have to pass between Threads)

    ThreadA gets created/started with a reference to MainApp
    ThreadB gets created/started with a reference to MainApp

    ThreadA continously reads the Property of MainApp ("If MainApp.CrossThread=1 Then DoSomething")

    ThreadB finishes first and wants to inform ThreadA.
    Code:
    'In ThreadB
    MainApp.CrossThread=2
    Of course untested, since i've never done anything like that in VB6
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  5. #5
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    1,973

    Re: [ADVANCED] Multi-threaded VB6

    Found something
    *Note* Objects in different apartments can only communicate with each other if a client passes them references to each other. In this case, cross-thread marshaling is used to provide synchronization. Cross-thread marshaling is almost as slow as cross-process marshaling.
    https://docs.microsoft.com/en-us/pre...361(v%3dvs.60)

    There you have it.
    Since every Thread runs in its own Apartment, you have to provide a Reference to each other.
    I'd go the way to pass the reference to ThreadB (If ThreadB has to notify ThreadA) to your ThreadA, with ThreadA continously reading that Property of ThreadB.
    It's kind of the same as with Parent- and child-forms: ThreadA would be the Parent, ThreadB would be the Child. ThreadB provides the Information, with ThreadA collecting the Information and then acting accordingly.
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  6. #6
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    I am trying to communicate between threads, but if thread A is busy and thread B tries to update thread A, thread B gets locked up until thread A finishes. I've tried using timers, custom events, nothing allows me to change memory on another thread without yielding (DoEvents).
    What do you mean by "update thread A"? Notify it? Which one is the main thread? Also, is this AxEXE used by another Standard EXE, or does it work alone as a multi-threaded standalone that is showing a GUI?

    I am not sure if you are using WaitForSingleObject(), but it's very common to use INFINITE, which could cause a deadlock; while 0 just checks the event and returns immediately.

  7. #7
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    1,973

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by qvb6 View Post
    Which one is the main thread?
    Exactly what i was thinking.
    From Pascal i'm used to having a MainThread which checks a Sync-Event in an infinite loop, and the ChildThreads can use that mechanism to pass on whatever information they want to pass to the MainThread, which itself can notify whichever ChildThread needs to be notified.
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  8. #8
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: [ADVANCED] Multi-threaded VB6

    The link that the OP posted shows a method of finding the main thread, but I was asking whether Thread A or B is the main thread. I too haven't experimented much with multithreading, especially communication between threads.

  9. #9
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    1,973

    Re: [ADVANCED] Multi-threaded VB6

    As far as i understood the Link of the OP: It shows searching for the MainApp, for it to be invoked only once (because of the Form it uses).
    But following the MS-Logic: Even the MainThread would be in its own Apartment? (<-- That's a Question!)
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  10. #10
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: [ADVANCED] Multi-threaded VB6

    On the first run, the form caption is changed to include the Process ID, and so other threads find this form by using the API function FindWindow(), and so would know they are not the main thread, and act accordingly.

  11. #11
    Lively Member
    Join Date
    Mar 2019
    Posts
    96

    Re: [ADVANCED] Multi-threaded VB6

    If you use alternative forms of threading then global variables are visible to all threads however this requires you to manage all your synchronization. When you say "communicate" what are you trying to pass around?

  12. #12
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    Just find a solid free-threaded object to implement a non-blocking queue. Free-threaded means both (or serveral) threads can call functions w/o any COM marshalling. There will be blocking (it's inevitable) but it will be internally implemented by the object, not by COM marshalling proxies.

    Here is a tip: ADODB.Recordset is such a free-threaded coclass.

    cheers,
    </wqw>

  13. #13

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    @ Zvoni, I have referenced the objects. Problem is as soon as one accesses the other, it deadlocks until the thread accessed is finished. Yes, the main thread has its own apartment, and the FindWindow code is so that two forms don't get loaded. VB actually calls sub main twice when multi-threading, and only once in IDE/non-multi...

    @ qvb6, update memory, call procedure, anything to update the thread from the other. Thread A is the main thread, though it doesn't seem to make a difference if I purposely lock thread A and try to update memory with B or B and update it with A. EXE is not used by another EXE. I am NOT using WaitForSingleObject(), never heard of it.

    @ vbwins / wqweto, why is it not subject to marshaling? But yes, that is what I am looking for. Can I do that without storing in a database? I need a non-blocking queue to pass events. The main thread has my GUI and the second has a web server that could be busy downloading pictures/video. The web server has to pass limited data to the GUI to change screens / info. True the GUI shouldn't be that busy that it deadlocks the web server while its trying to update, it just seems like the best way to write it is with a non-blocking queue. MS documentation says that raisevent should be non-blocking if picked up by another thread, but it doesn't seem to work for me.

  14. #14
    Frenzied Member
    Join Date
    Feb 2015
    Posts
    1,360

    Re: [ADVANCED] Multi-threaded VB6

    Please, notice to this module. There is AsynchDispMethodCall function which uses callback mechanism to notify the main thread about the call-completion.
    The main thread posts the special message to child thread and returns immediately. When the child thread has processed the call it sends notify to the main thread.
    You can create a thread with this asynchronous call dispatcher which delivers the messages to thread and returns immediately.

  15. #15
    Member
    Join Date
    May 2019
    Posts
    50

    Re: [ADVANCED] Multi-threaded VB6

    Run-time error '453':

    Can't find DLL entry point IStream_Reset in Shlwapi

  16. #16

  17. #17
    Member
    Join Date
    May 2019
    Posts
    50

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by the trick View Post
    what's the os?
    xp sp3

  18. #18
    Member
    Join Date
    May 2019
    Posts
    50

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by the trick View Post
    what's the os?
    xp sp3

  19. #19
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    @ vbwins / wqweto, why is it not subject to marshaling? But yes, that is what I am looking for. Can I do that without storing in a database? I need a non-blocking queue to pass events. The main thread has my GUI and the second has a web server that could be busy downloading pictures/video. The web server has to pass limited data to the GUI to change screens / info. True the GUI shouldn't be that busy that it deadlocks the web server while its trying to update, it just seems like the best way to write it is with a non-blocking queue. MS documentation says that raisevent should be non-blocking if picked up by another thread, but it doesn't seem to work for me.
    Free-threaded means methods can be called from arbitrary appartment simultaneously. ADO coclasses are marked Both threaded AFAIK which is the same for your use-case.

    There are disconnected client-side ADODB.Recordsets that are something like an array of UDTs w/ named fields. These are completely disconnected from any DB.

    In your GUI thread just create a client-side recordset w/ Set m_rsQueue = New ADODB.Recordset : m_rsQueue.Fields.Append ... : m_rsQueue.Open and pass it along w/ a post-back hWnd to your worker thread (somehow). Your worker thread just push data to queue w/ rs.AddNew ... and PostMessage hWndNotify, WM_CHAR, ... to notify GUI there are pending notifications.

    In your GUI thread on your txtNotify_KeyPressed check m_rsQueue content and remove records as these are being processed.

    cheers,
    </wqw>
    p.s. When you see a reply with multiple "just"s, this must be a red flag for you that probably the implementation is not going to be "just" that simple :-))

  20. #20
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,405

    Re: [ADVANCED] Multi-threaded VB6

    It's also perfectly possible in (VB6-)STA-threading, to "break out of TLS restrictions and COM-marshalling" -
    then working against a shared Memory-area (by passing the pointer to an allocation, which is managed by the main-thread).

    The easiest way to read-from/write-to such a shared Mem-area is via an UDT-definition,
    which in turn is accessed via a SafeArray.

    The Main-Thread would allocate (and later destroy) this UDT-SafeArray and work against it "normally" (non-virtual) -
    whereas the secondary threads could each span their own virtual safe-array across this pre-allocated area via the usual safearray-pointer-mapping-techniques.

    Note, as soon as you use such an approach, the usual rules with ensuring concurrent access to that mem-area will apply
    (as in other, freethreaded languages).

    Therefore - a separated "Data-Holder-only-ClassInstance" (which will not block "long", because it only does InMemory-saving/reading)
    is usually easier to implement (and share) within the confines of VB6-STAs.

    Olaf

  21. #21

  22. #22
    Member
    Join Date
    May 2019
    Posts
    50

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by The trick View Post
    Try to replace
    Code:
    Private Declare Function IStream_Reset Lib "Shlwapi" ( _
                             ByVal pstm As Any) As Long
    to
    Code:
    Private Declare Function IStream_Reset Lib "Shlwapi" Alias "#213" ( _
                             ByVal pstm As Any) As Long
    Works Perfectly, Thank you.

  23. #23

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    How do you use safe array in VB6? I do already want to pass mainly UDTs. Otherwise I will look into the recordset solution.

    Edit: I was considering a data only class but it seemed overkill and wont it need its own thread?
    Last edited by PsuFan; May 10th, 2019 at 10:16 AM.

  24. #24
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,405

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    How do you use safe array in VB6? I do already want to pass mainly UDTs. Otherwise I will look into the recordset solution.
    I usually handle this with a few helpers in a *.bas-Module... (e.g. named modSharedArrays.bas)
    I'd recommend, to also define the UDTs Publically within that *.bas (those which are shared via the Array) -
    and then reference that very same Code-Module also in your Thread-Dll-project (so that changes on the UDT-Members are reflected there).

    Here an example, what this *.bas might contain...
    Code:
    Option Explicit
    
    Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (P() As Any) As Long
    Declare Sub BindArray Lib "kernel32" Alias "RtlMoveMemory" (PArr() As Any, ByVal pSrc&, Optional ByVal CB& = 4)
    Declare Sub ReleaseArray Lib "kernel32" Alias "RtlMoveMemory" (PArr() As Any, Optional pSrc& = 0, Optional ByVal CB& = 4)
     
    Public Type tMyUDT
      SomeLong As Long
      SomeString As String
    End Type
    Now, in your Main-Thread (here simulated by a Form):
    Code:
    Option Explicit
     
    Private SharedArrMain() As tMyUDT
    
    Private Sub Form_Load()
      'redim and allocate this only once - before you start "sharing it in thread-classes"...
      ReDim SharedArrMain(0 To 1)
      '...then leave the above allocation alone, for the lifetime of the threads
    End Sub
     
    Private Sub Form_Click()
      Dim oThread As New cThread
          oThread.InitSharedMemArea ArrPtr(SharedArrMain) 'pass the ArrPtr of the main-thread-allocation
          oThread.Test 'this method writes into the shared-memory using the class-internal (virtual) Array
          
      With SharedArrMain(0) 'we are back - and check the main-allocation to see what we got from the virtual-array-test above
        Caption = .SomeLong & " " & .SomeString
      End With
    End Sub
    Now, a Thread-Object (here simulated via a little Class, named cThread) could contain:
    Code:
    Option Explicit
    
    Private SharedArr() As tMyUDT
    
    Public Sub InitSharedMemArea(pSharedArr As Long)
      If pSharedArr Then BindArray SharedArr, pSharedArr
    End Sub
    
    Public Sub Test()
      Debug.Print "Ubound-of-SharedArr: "; UBound(SharedArr)
      With SharedArr(0)
        .SomeLong = .SomeLong + 1
        .SomeString = .SomeString & Chr$(64 + .SomeLong)
      End With
    End Sub
    
    Private Sub Class_Terminate() 'cleanup of the virtual ArrBinding
      ReleaseArray SharedArr
    End Sub
    Note, that I left out the wrapping of Member-access via CriticalSections...
    Whether you'll need those - depends on the type of UDT-members - but also on your concrete threading-scenario
    (e.g. in larger RingBuffer-scenarios, or when you assign each thread its own Shared-Array-Index, you could get away without them..)

    Quote Originally Posted by PsuFan View Post
    Edit: I was considering a data only class but it seemed overkill and wont it need its own thread?
    Such a "shared-data-class" would run on it's own thread - that's right (it needs to, to be reachable from "everywhere" in a non-blocking-manner) -
    but it would only occupy just that one thread (and then acting as a singleton).

    Note, that the example I've posted for the shared-array-stuff will work only, when the VB6-threading-approach runs entirely InProcess.
    If you use AX-Exe-Threading in "Multi-Process-Mode" - then:
    - the approach would need to be changed to FileMapping-allocations
    - or you could use the just described Data-Only-Singleton-ClassInstance (which was instantiated on its own thread).

    HTH

    Olaf
    Last edited by Schmidt; May 10th, 2019 at 10:51 AM.

  25. #25

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    I was running Ax-EXE threading. How do I know if I am multi-process-mode?

    Why does the data module need its own thread? If the two threads have access to the same memory locations, cant they just use them without blocking/deadlocking?

    Thanks for the help

  26. #26
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,405

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    I was running Ax-EXE threading. How do I know if I am multi-process-mode?
    If you create AX-Exe-Class-instances via the New Keyword (e.g. from a Std-Exe) -
    then those (Thread-)Class-Instances run "Out-Of-Process" (of your Std-Exe).

    The approach you linked to in your first post - is InProcess-AxExe-Threading,
    because the Demo is running "from inside an AX-Exe in GUI-Mode" +
    it starts new Ax-Exe-Class-Instances internally via CreateObject(AxExe.ProgId)

    The Demo is a bit "clumsy" though - especially the FindWindow-fiddling in Sub Main
    is completely unnecessary, because a simple test like below is enough:
    Code:
    Sub Main()
      If App.TaskVisible Then fMain.Show 'follow-up Sub Main-entries will have App.TaskVisible = False
    End Sub
    Quote Originally Posted by PsuFan View Post
    Why does the data module need its own thread?
    First let's make it more clear, what "DataModule" we're talking about.

    The little Demo in my prior posting is not "Shared-DataClass-based"
    (but relies on SafeArray-Ptr-Passing from a normal VB-Array-allocation which was generated in the Main-Thread).
    So this is the faster shared-data-approach, which avoids COM-marshalling (since it is not "AxExe-DataClass-based") -
    but you will need to protect your Shared Array-Data "by hand" (via Critical Sections) - so the speed-advantage comes at a cost.

    The other approach which was mentioned is the easier one - because concurrent access is "fully managed" under the covers.
    This is the "AxExe-DataClass-based" approach, where COM handles the access for you.
    And the Singleton-like DataClass-instance should neither be instantiated on the Main-Thread (the GUI-thread) -
    nor should it be instantiated on one of the Worker-threads - because any of these threads might "enter a longer processing-routine"
    (and whilst being "in that routine" the DataClass-instance on such a thread would not be reachable from other threads).
    Note that I wrote instantiated on in the last paragraph - which is different from "passed into" or also "used within" (a thread).

    Ok - long story short - the Singleton-AxExe-DataClass should be instantiated on its own thread (via CreateObject),
    to guarantee a thread which will never "enter any longer processing-routines" (because this Class does not contain any processing-routines).

    Quote Originally Posted by PsuFan View Post
    If the two threads have access to the same memory locations, cant they just use them without blocking/deadlocking?
    As said - in case of:
    - the SafeArray-Ptr-Passing-approach, there is no blocking (other than your own CriticalSection-handling)
    - in case of the Singleton-AxExe-DataClass-instance, there will also be no blocking (when it runs on its own STA)

    Here is an example for the latter (simpler) approach in an "InProcess-AxExe-Project":
    AxExeInProcessThreads.zip

    HTH

    Olaf

  27. #27

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    Thanks for all the help. Sorry for all the questions, some of this stuff is barely English to me lol. So you're recommending the threaded data class? How (well) does a three threaded app run on a dual or single threaded CPU? I may introduce a fourth thread for syncing online media as well... I didn't get to checkout your example but I will. I thought the Ms example was crazy too, I already eliminated the hidden form but didn't know about app.taskvisible! Are you sure it works multi-thread? I read in my link above that App is not shared between threads thus app.threadid gives unique numbers. I will have to test this.

  28. #28

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    Interesting, I didn't think to use sub main to activate form instead of class... How many threads does this use, 4?

    Code:
    Private Sub Form_Activate() 'use this instead of Form_Load, in case you want to start threads at Form-Startup-time
      Set SharedData = CreateObject("AxExeInProcess.cSharedData") 'the SharedData-Singleton needs its own thread, to work non-blocking
      Set Worker1 = CreateObject("AxExeInProcess.cWorker").Init("Worker1", SharedData)
      Set Worker2 = CreateObject("AxExeInProcess.cWorker").Init("Worker2", SharedData)
    End Sub
    your app.taskvisible works perfectly!

  29. #29
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    your app.taskvisible works perfectly!
    Unfortunately you cannot drop AxExe's in users Documents folder i.e. make it portable (and manifests won't help) -- it still needs COM registration with a setup etc. If you don't register it and start it directly, it will automagically self-register successfully if you are an admin. If you are not an admin and the COM registration is not present registry it will bomb with obscure error from VB6 run-time that cannot be trapped.

    Clearly the AxExe's self-registration feature was conceived in Win9x era.

    cheers,
    </wqw>

  30. #30

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    I was wondering why it didn't start on my target computer... Thanks

  31. #31
    Addicted Member
    Join Date
    Jan 2015
    Posts
    170

    Re: [ADVANCED] Multi-threaded VB6

    so local support need some hex fix in code, but because that code is not created by me, so i can not place it here.
    you can see it here, but it is Chinese url, and also the code. maybe quit difficult for u to understand
    Last edited by loquat; May 12th, 2019 at 08:35 AM.

  32. #32
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by wqweto View Post
    Unfortunately you cannot drop AxExe's in users Documents folder i.e. make it portable (and manifests won't help) -- it still needs COM registration with a setup etc. If you don't register it and start it directly, it will automagically self-register successfully if you are an admin. If you are not an admin and the COM registration is not present registry it will bomb with obscure error from VB6 run-time that cannot be trapped.

    Clearly the AxExe's self-registration feature was conceived in Win9x era.

    cheers,
    </wqw>
    Per COM rules, HKEY_CURRENT_USER(HKCU) is checked first for registration before checking HKLM(This is documented here, and also in MSDN October 2001, search for title "Classes and Servers"), so it's possible to make an ActiveX project "portable" without manifest, unless Microsoft broke things.

    Also, I know that AxDLL's don't auto-register, but OCX do auto register, and one could create the necessary HKCU entries in Sub Main() before loading a form containing the EXE, or instantiating the AxDLL.

    As for AxEXE, I am not sure, but I think that it doesn't auto-register, you have to use the command line option /regserver, or create the necessary HKCU entries in Sub Main(). So, I think only OCX files do auto-registration.

  33. #33
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by qvb6 View Post
    As for AxEXE, I am not sure, but I think that it doesn't auto-register, you have to use the command line option /regserver, or create the necessary HKCU entries in Sub Main(). So, I think only OCX files do auto-registration.
    An AxEXE does auto-register w/o any option. The difference is that when you pass the option it does *not* start the start-up form/sub main.

    HKCU entries of course work so a COM client can instantiate our out-of-proc coslasses/servers from out AxEXE but still the VB6 run-time insist on registering in HKLM. If it doesn't find the entries in HKLM it does not check HKCU and skip writing in HKLM. It's attempt on startup strighforward fails under non-priviledged users.

    cheers,
    </wqw>

  34. #34

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    Anyone know why when I RaiseEvents to other threads, it still happens synchronous?

    https://docs.microsoft.com/en-us/pre...370(v%3dvs.60)

  35. #35
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    Only events? Did you manage to call methods/properties asynchronously? That would be a first :-))

    Usually for async when you call a method on a worker thread it starts a fire-once timer and returns immediately, then the processing begins on the timer tick and a notification is posted when complete (various options for this).

    cheers,
    </wqw>

  36. #36

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    I don't think that will work non-blocking either though. If I purposely block the main thread, and try and call a function from a worker thread to the main thread that does nothing, it blocks the worker thread. With events or timers...

    I have been building with Schmid's method but the documentation says you should be able to do it with events which would be so much easier/better.
    Last edited by PsuFan; May 13th, 2019 at 06:47 PM.

  37. #37
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,582

    Re: [ADVANCED] Multi-threaded VB6

    PostMessage does not block if main thread is busy. Another option is main thread to poll on one or several hEvents which get signaled from worker threads. The latter is more scalable but the first one is easier to implement.

  38. #38

    Thread Starter
    Member
    Join Date
    Apr 2015
    Posts
    38

    Re: [ADVANCED] Multi-threaded VB6

    Cool, can I send custom messages? How do you receive them on main thread? That would eliminate timers checking for updates but would likely need to use your recordset solution or the extra thread shared memory to pass lots of data like UDTs.

  39. #39
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    444

    Re: [ADVANCED] Multi-threaded VB6

    Not sure if VB internally uses SendMessage, but from SendMessage Remarks section: "If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more information on nonqueued messages, see Nonqueued Messages."

    PostMessage doesn't switch threads.

  40. #40
    Frenzied Member
    Join Date
    Feb 2015
    Posts
    1,360

    Re: [ADVANCED] Multi-threaded VB6

    Quote Originally Posted by PsuFan View Post
    Cool, can I send custom messages? How do you receive them on main thread? That would eliminate timers checking for updates but would likely need to use your recordset solution or the extra thread shared memory to pass lots of data like UDTs.
    Just create a window (HWND_MESSAGE) and process the messages in its window proc.
    Brief review of concept:
    Code:
    ' // Class CYourClass
    
    Dim tClass      As WNDCLASSEX
    
    ' // Register class
    tClass.cbSize = Len(tClass)
    tClass.hInstance = App.hInstance
    tClass.lpfnwndproc = FAR_PROC(AddressOf AsyncWndProc)
    tClass.lpszClassName = StrPtr(YOUR_WINDOW_CLASS_NAME)
    tClass.cbWndExtra2 = 4  ' // Reference to class instance
    
    RegisterClassEx tClass
    
    . . .
    
    ' // Create window
    m_hWndAsync = CreateWindowEx(0, StrPtr(YOUR_WINDOW_CLASS_NAME), 0, 0, 0, 0, 0, 0, _
                                 HWND_MESSAGE, 0, App.hInstance, ByVal 0&)
    
    ' // Set reference to class instance
    SetWindowLong m_hWndAsync, 0, ObjPtr(Me)
    
    . . .
    
    ' // Your thread func
    ' // Post to main thread and return immediatelly
    PostMessage m_hWndAsync, WM_ID_ASYNCH_METHOD, ..., ...
    
    . . .
    
    ' // Window proc of async window in main thread
    Public Function AsyncWndProc( _
                    ByVal hwnd As Long, _
                    ByVal uMsg As Long, _
                    ByVal wParam As Long, _
                    ByVal lParam As Long) As Long
        Dim cObj    As CYourClass
        
        ' // Get object from window bytes
        vbaObjSetAddref cObj, ByVal GetWindowLong(hwnd, 0)
        
        Select Case uMsg
        Case WM_ID_ASYNCH_METHOD
            
            cObj.Method wParam, ....
            
        Case Else
            AsyncWndProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
        End Select
        
    End Function
    Alternatively you could use APC queue but main thread should be in the alertable state.

Page 1 of 2 12 LastLast

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
  •  



Featured


Click Here to Expand Forum to Full Width