No announcement yet.

Multi-thread in VB6 source code comments

  • Filter
  • Time
  • Show
Clear All
new posts

    Multi-thread in VB6 source code comments

    Comments on multi-threading using VB6 in source code forum.
    Add multi-threading to VB6. It works in or outside the VB6 environment.
    Try ending the VB6 program while threading.

    Multi-threaded PB code with a VB6 front-end.

    Last edited by Mike Doty; 10 Oct 2009, 11:14 AM.

    I have been informed this may be unstable.
    If you know of a way to brute force test this, please let me know.
    I've been doing this for a couple of years without any problems.
    I think some of the other solutions were unstable.



      I have not tried your code.
      In the past I spent quite a time to try to do the same. VB6 is not thread safe, period. You may succeed with a multithreaded PB DLL when you use working threads that do not return any value to VB6. When I needed to return value the only working solution I found was to create a textbox in VB6, pass the handle of the textbox to the PB DLL and write the value in the PB DLL to the textbox. Than I used the Textbox_Change event to get the value in VB6 and clear the textbox. I also found that the exact same solution might appear runnning safely from one VB6 application but not from another depending on the controls and components the VB6 program uses.

      Peter Redei


        Actually SP2 of VB5 was thread safe but they messed it up again in VB6 that does not mean it can't be done. Results from individual threads can be passed back to a single non exported function say by sending a message to a hidden dialog which causes it to read a synchronised global (i.e. with a mutex), that function can then forward the information or results to a custom written callback in the VB6 program, alternatively you could trigger an event in VB6 which causes it to interogate the DLL for results but that is messier.


          Sounds great.
          Enhance or replace my code at anytime!

          I'd work on it now, but caught up in adding PDF support.
          Thanks to MM for mentioning haru and Jose Roca for headers, demo and more.

          You guys are way ahead of me in the CALLBACK area. I've only
          used threads for transmitting/receiving files, allowing buttons and menus
          to react without waiting and splash screens. This is probably why I haven't had any problem.
          I will soon attempt updating an ActiveX grid control for VB6 from a thread.
          I certainly would like to add more to this threading DLL.
          All other tested code goes into another DLL and is also callable by VB6.
          I can also compile PowerBASIC code from a network terminal giving me two monitors.

          This is the best of two worlds.
          PowerBASIC on one monitor and VB6 environment on the other monitor working together.
          Last edited by Mike Doty; 11 Oct 2009, 11:23 AM.


            Mike and Peter
            It is actually quite simple, but please don't confuse the word CallBack with Windows messages or GUI, it is just a function that you can call with CALL DWORD in PB and actually there is no difference if the DLL is being used in a PB program or in fact if the whole thing is a single exe, You just need to establish the functions address. In VB6 you do it like this in a module (not a form) you create the callback function
            Public Function MyDLLCallBack(Data1 as, Data2 as, etc etc) as Long of course the actual name is irrelevant.
            Before doing anything else with the DLL you would initialise it like
            er = InitMyDLL(AddressOf MyDLLCallBack, any other useful settings)

            In my last post I suggested that threads reported to a single non-exported funtion but its not always needed but was one suggestion for queueing the data going back to VB6 in case the callback is not truely re-entrant and two threads could send data at about the same time. Actually each thread can report back directly with a single global flag protected by a mutex. Any thread sending data would first check the flag to see if the receiving program was ready to receive data if so it first sets the flag to False and sends the data. The receiving program after it has finished with the data simply calls an exported funtion like ICanNowAcceptData to set the flag back to True.
            Of course the call from PB and any thread is a standard CALL DWORD to the saved address. If you have threads doing vastly different things then you can have multiple callbacks.
            Common sense is needed, as VB6 itself is not thread safe you don't pass or use Windows handles or any other addresses from it other than the callback address.


              vb 6 is not reentrant. any threaded dll you create will cause a gpf one way or another. There is a hack I put together that is the only real solution to the problem unless of course pb builds in the ability to trigger an internal event from outside the class.
              Sr. Software Development Engineer and Sr. Information Security Analyst,
              CEH, Digital Forensic Examiner


                I have never GPF'ed.
                I call other PB routines from the thread.


                  I agree with Mike Thomas you will note that the callback in my method is never called in a rentrant way, quote two different ways to to ensure that.
                  The first obvious reason your simple statement is wrong is that VB6 can be used as a COM server and thus be called by many programs at the same time. The COM engine does the neccessary marshelling to avoid the problem you quote. You will find many methods on the net including from MS staff of how to make VB6 multi-threaded. As you say triggering an event is one of them, no real hack needed or COM, it can be done by simply sending a Windows message to an esisting control that understands it, I have seen Key_Down used for that purpose with VB to VB, the callback correctly done is simpler.


                    Update PbThreadClose to also update gHandle array in a critical section.
                      LOCAL result AS LONG
                      THREAD CLOSE gHandle(ElementNumber) TO result   '0 = failure
                      IF result THEN
                        gHandle(ElementNumber) = 0 'make slot available
                        FUNCTION = result
                      END IF
                    END FUNCTION


                      THis function here..
                        FUNCTION = THREADCOUNT
                      END FUNCTION
                      .. is not really accurate, because of what the PB THREADCOUNT() function is counting.

                      Here's some code which counts actual thread OBJECTs and will include threads created in other code modules:

                      Real Thread Count for this process
                      FULL BBS thread:
                      RealThreadCount:Full Thread

                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]


                        I believe extra threads are reported that way and the thread count may never reach 1. VB6 will not know when it is okay to end.


                          > VB6 will not know when it is okay to end.

                          Your VB program can ...

                          WaitForMultipleObjects (array of thread handles created in your DLL).

                          That WILL hang the VB UI unless you do something cool, as "Wait For" means WAIT.

                          I'd probably use (hell,I have used) the MsgWaitForMultipleObjects() function in my message loop to "wait for all my worker threads to complete but keep my UI alive so I don't get that dopey white rectangle" but as I recall, VB6 does not provide the programmer access to the message loop. So I don't know what I would do here, except maybe try to sell an upgrade to the UI itself.

                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]


                            Hey! this thing popped up again? its been a while since I commented or saw this thread...

                            Simply put VB6 is not re-entrant, this means that you can do whatever you want, when ever you want but the main problem is...

                            COM ERRORS ARE NOT THREAD SAFE

                            This is the issue when dealing with multi-threaded VB6 apps... if you can get past that then it is thread safe...

                            So, if your VB6 App decides there is a COM error and your PB dll also decides there is a com error then the COM ERROR Stack will be smashed with two competing errors...

                            if you can avoid COM errors then your application will live happy and bee happy....

                            But the moment you have a COM error then good luck. There are two ways to avoid this... 1. only use api's that don't issue com errors... or 2. hack the assembly output from the C1 compiler before the C2 compiler gets a hold of a way that makes the COM ERROR stack multi-threaded.

                            There used to be a doc on that somewhere, don't recall where - don't really care these days either...

                            Again, if none of this applies to you.... don't look into it any further... just my two cents

                            Sr. Software Development Engineer and Sr. Information Security Analyst,
                            CEH, Digital Forensic Examiner


                              >COM ERRORS ARE NOT THREAD SAFE

                              Given that is true...

                              Can't you avoid that by initializing COM on a separate thread of execution and executing "possibly conflicting COM operations" there?

                              Maybe someone who knows COM way better than do I can answer that.

                              The re-entrant thing, PB code always supports re-entrant execution; which does NOT mean you can forget about it and do things your own way without considering what happens when you take advantage of this feature.

                              Just FWIW, CONTROL SET TEXT and SendMessage(hwnd_on_this_thread) both require re-entrant execution. (Hmm, so you were doing re-entrant applications and didn't even know it, huh?)

                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]


                                Good point but remember the dates of the posts. Back then creating a COM server with PB was extremely difficult so the issue you raise wasn't considered.