Results 1 to 22 of 22

Thread: VB6 Threading, using the small DirectCOM.dll-HelperLib

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    VB6 Threading, using the small DirectCOM.dll-HelperLib

    Just for those who want to try a proven approach, which works reliably (and comparably simple)
    in spanning up STAs (Single-Threaded-Apartments) for over 10 years now (one can use his own
    VB6-compiled AX-Dlls which provide a Class-Instance that runs on said STA - no Assembler-Thunking,
    no TypeLibs and also no "special Dll-Exports" are needed - it's aside from a few API-calls just straight VB-Code).

    The Thread-Class-Instances in question are always created Regfree in this case (so,
    no Setup is needed - just ship your Thread-Dlls alongside DirectCOM.dll in a SubFolder
    of your App).

    The Demo here tries to show not only how to create the STA-threads with a Class-
    Instance in it, but also how to share Memory with the Applications Main-Thread
    (which is the fastest way of cross-thread-communication).

    The implementation of the Main-App is using a separate (Private) Wrapper-Class
    for handling the "Remote-Thread" (offering Properties to wrap the shared Memory-area,
    and such a Class will also automatically close the thread it wraps, in case it is itself terminated).

    That allows for cleaner Code in the "Thread-consuming-instance" (in our case the Apps fMain-Form).

    The Code for the ThreadLib.dll on the other hand - (this is the AX-Dll which provides a Public
    cThread-Class, which will finally run on its own threaded Apartment) - is contained in the
    \Bin\... SubFolder of the Zip.

    Just leave this Bin-SubFolder as it is, when you run the Main-Apps *.vbp File.

    Here's the Code for the Demo:
    VB6ThreadingDirectCOM.zip

    And here is a ScreenShot (the colored Forms are created inside the 4 Threads - and perform
    an endless loop, to show some kind of "Plasma-Effect" - just to put the threads under stress a bit).



    Have fun (and just ask when you have any questions - though I tried to comment the Demo well enough, I hope).

    Olaf
    Last edited by Schmidt; May 22nd, 2015 at 04:27 PM.

  2. #2

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by The trick View Post
    Hello Schmidt! Thanks for cool code! it supported events?
    No - the Demo above does not support "Classic VB-Events" currently (the higher-level
    Threading-Support of the vbRichClient5.dll would allow for that though).

    But the Demo as it currently is, supports "shared state" (over the shared Memory-Area,
    behind the VB-Array TI() - which both sides have access to).

    So, "Event-like reactions to State-Changes" can be implemented quite easily...
    And the Demo does so already, by reporting in the Main-Form the state-changes
    on the FPS-Member of the shared Mem-area - and in the opposite direction,
    by reacting within the Threads to a state-change in the CancelThread-member
    when it was set in the Main-Thread.

    Olaf

  4. #4
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    No - the Demo above does not support "Classic VB-Events" currently (the higher-level
    Threading-Support of the vbRichClient5.dll would allow for that though).
    I am very interested in Threading-Support in RC5. Is there an example for this?

    Thanks for the great work you've done here.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Olaf, also a bit interested for a specific purpose. Any suggestions welcomed.

    Scenario: image format. Manually parsing file to extract animation frames, frames composed to an image-strip. The image strip is basically a 32bpp bitmap data, bytes only, ( (FrameWidth* frameCount) x FrameHeight) and will be contained in COM stream

    I imagine myself using threading to create this image-strip in the background. The COM stream is created on the main thread but populated from the background thread. The COM stream is not guaranteed to be accessible by hGlobal, may be virtual via IStorage. A timer on the main thread can check for a flag set by the background thread when task is completed.

    Are COM objects shareable between the main thread and background thread? Any tips on GDI+ usage between threads and sharing of GDI+ object handles?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by LaVolpe View Post
    Are COM objects shareable between the main thread and background thread? Any tips on GDI+ usage between threads and sharing of GDI+ object handles?
    For the latter question: GDI+ is "partially" thread-safe. You can access objects from multiple threads, but you must perform your own synchronization.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  7. #7
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    LaVolpe, i've made the example for you, but only it use the my methods of multithreading.
    This program scans the specified directory and retrieves the thumbnails of the pictures from this directory. The pixels data of each thumbnail is stored to an IStream object (rather the object that support IStream interface). Since the size and the pixels format of the all thumbnails is indentical, you can simply calculate the offset (Width(Stride)*Height*BitsPerPixels\8). All work performs in the different thread. Main thread gets the notifications. All code doesn't contain the error handlers and other checks because it is example.
    Code:
    Option Explicit
    
    Public Const ThumbnailSize          As Long = 128
    
    Public Enum UserMessages
        SET_LABEL_CAPTION = WM_APP
        SET_PROGRESS
        ADD_TO_LIST
    End Enum
    
    Public Type UserData
        NotifyWnd                   As Long
        FindPath                    As Long
        Stream                      As IStream
        Progress                    As Single
    End Type
    Public Type ThreadData
        NotifyWnd                   As Long
        FindPath                    As String
        Stream                      As IStream
        Progress                    As Single
    End Type
    
    Public Function BackgroundThread( _
                    ByRef param As ThreadData) As Long
        Dim fso         As FileSystemObject
        Dim curFolder   As Folder
        Dim curFile     As File
        Dim gdipToken   As Long
        Dim gdipStartup As GdiplusStartupInput
        Dim image       As Long
        Dim thumb       As Long
        Dim rc          As RECTL
        Dim bd          As BitmapData
        Dim fileIndex   As Long
        Dim pointer     As Long
        
        gdipStartup.GdiplusVersion = 1
    
        GdiplusStartup gdipToken, gdipStartup
    
        Set fso = New FileSystemObject
        Set curFolder = fso.GetFolder(param.FindPath)
    
        rc.Right = ThumbnailSize
        rc.Bottom = ThumbnailSize
    
        For Each curFile In curFolder.Files
            ' // Set label caption
            PostMessage param.NotifyWnd, SET_LABEL_CAPTION, Len(curFile.Name), ByVal SysAllocString(ByVal StrPtr(curFile.Name))
            ' // Open image
            If GdipLoadImageFromFile(StrPtr(curFile.Path), image) = 0 Then
    
                If GdipGetImageThumbnail(image, ThumbnailSize, ThumbnailSize, thumb) = 0 Then
    
                    If GdipBitmapLockBits(thumb, rc, ImageLockModeRead, PixelFormat32bppARGB, bd) = 0 Then
                        
                        pointer = param.Stream.Seek(0, STREAM_SEEK_CUR) * 10000
                        
                        param.Stream.Write ByVal bd.scan0, bd.stride * bd.Height
                        
                        param.Progress = fileIndex / curFolder.Files.count
                        
                        PostMessage param.NotifyWnd, SET_PROGRESS, param.Progress * 100, ByVal 0&
                        PostMessage param.NotifyWnd, ADD_TO_LIST, pointer, ByVal SysAllocString(ByVal StrPtr(curFile.Name))
                        
                        GdipBitmapUnlockBits thumb, bd
                        
                    End If
    
                    GdipDisposeImage thumb
    
                End If
    
                GdipDisposeImage image
    
            End If
    
            fileIndex = fileIndex + 1
    
        Next
        
        PostMessage param.NotifyWnd, SET_PROGRESS, 100, ByVal 0&
        param.Progress = 1
        
    End Function
    This function is performed in the background thread. I've used the similar types ThreadData and UserData in oreder to avoid string freeing in the main thread.
    Code:
    Option Explicit
    
    Dim WithEvents WndHook  As clsTrickSubclass2
    
    Dim ThreadData  As UserData
    
    Private Sub cmdSplit_Click()
        Dim hThread As Long
        
        Set ThreadData.Stream = Nothing
        
        CreateStreamOnHGlobal 0, True, ThreadData.Stream
        
        ThreadData.NotifyWnd = Me.hWnd
        ThreadData.FindPath = SysAllocString(ByVal StrPtr(txtPath.Text))
        ThreadData.Progress = 0
        
        hThread = vbCreateThread(0, 0, AddressOf BackgroundThread, VarPtr(ThreadData), 0, 0)
        
        CloseHandle hThread
        
        If hThread Then
            cmdSplit.Enabled = False
            lstImages.Enabled = False
            lstImages.Clear
        End If
        
    End Sub
    
    Private Sub Form_Load()
        
        Set WndHook = New clsTrickSubclass2
        WndHook.Hook Me.hWnd
        
    End Sub
    
    Private Sub lstImages_Click()
        Dim pointer As Long
        Dim bitmap  As Long
        Dim gr      As Long
        Dim dat()   As Byte
        
        If ThreadData.Progress <> 1 Or lstImages.ListIndex < 0 Then Exit Sub
        
        pointer = lstImages.ItemData(lstImages.ListIndex)
        
        ReDim dat(ThumbnailSize * ThumbnailSize * 4 - 1)
        
        ThreadData.Stream.Seek CCur(pointer) / 10000@, STREAM_SEEK_SET
        ThreadData.Stream.Read dat(0), UBound(dat) + 1
        
        picThumbnail.Cls
        
        If GdipCreateBitmapFromScan0(ThumbnailSize, ThumbnailSize, ThumbnailSize * 4, PixelFormat32bppARGB, dat(0), bitmap) = 0 Then
            
            GdipCreateFromHDC picThumbnail.hdc, gr
            GdipDrawImageI gr, bitmap, (picThumbnail.ScaleWidth - ThumbnailSize) \ 2, (picThumbnail.ScaleHeight - ThumbnailSize) \ 2
            GdipDisposeImage bitmap
            GdipDeleteGraphics gr
            picThumbnail.Refresh
            
        End If
        
    End Sub
    
    Private Sub WndHook_WndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long, Ret As Long, DefCall As Boolean)
        Dim tmpStr  As String
        
        Select Case Msg
        Case UserMessages.SET_LABEL_CAPTION
        
            GetMem4 lParam, tmpStr
            lblProgress.Caption = tmpStr
        
        Case UserMessages.SET_PROGRESS
            
            picProgress.Cls
            picProgress.Line (0, 0)-(wParam, 1), , BF
            
            If wParam = 100 Then
            
                cmdSplit.Enabled = True
                lstImages.Enabled = True
                
            End If
        
        Case UserMessages.ADD_TO_LIST
        
            GetMem4 lParam, tmpStr
            lstImages.AddItem tmpStr
            lstImages.ItemData(lstImages.NewIndex) = wParam
            
        End Select
        
    End Sub
    The modules modMultiThreading.bas and EXEInitialize.tlb you can download hereand clsTrickSubclass2.cls here.
    Name:  ??????????.PNG
Views: 3418
Size:  57.4 KB
    Attached Files Attached Files

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    @The Trick. I'll download and play this weekend. In my case, I will not have a hWnd to pass. My intent is background threading in a windowless usercontrol and not too sure I want to subclass the control's container. I know I can create an API window, i.e., Static window class for example, for this purpose instead. However, your comments for your vbCreateThread function states it will not work in IDE? Is that still correct?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by LaVolpe View Post
    In my case, I will not have a hWnd to pass. My intent is background threading in a windowless usercontrol and not too sure I want to subclass the control's container.
    hWnd is needed only for communication between threads. You can use flag or something else (system Event or Mutex). If you don't worry about the additional dependencies (tlb or dll), you can use the object in background thread and generate event to main (if you had read the my first article about multithreading, there is the example).
    Quote Originally Posted by LaVolpe View Post
    I know I can create an API window, i.e., Static window class for example, for this purpose instead.
    HWND_MESSAGE, also you can use any method of the calling in the specified context. Using window i ensure the manual marshaling. You can use any other methods.
    Quote Originally Posted by LaVolpe View Post
    However, your comments for your vbCreateThread function states it will not work in IDE? Is that still correct?
    This function will perform in same thread in IDE, because IDE doesn't support the multithreading debug (i mean not-compiled code). You can create the dll, and debug in the ide through CreateThread, here is example.

  10. #10
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    The Trick:

    I find it so difficult to understand the code and comments here. Is there a newbie-friendly thread regarding multithreading stuff in VB6. I'd really like to learn and use. I know it involves some basic(maybe advanced?) knowledge of COM, and I have read some articles from MSDN about it, but still I am having trouble here.

    I understand that to fully know how it works takes more time but right now I just hope to find something that I can use right away. My current problem is to send HTTP requests asynchronously, wait for each response, and process them after all response are received. This will accelerate my program a bit I guess.



    Olaf:

    I checked classes in RC5 and got:

    Code:
    cThreadHandler
    cThreadInit
    cThreadMethods
    cThreadProxy
    seems they work with:

    cRegFree
    'The DirectCOM methods are also incorporated in RC5?
    An easy example will be much appreciated!!

  11. #11
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by bPrice View Post
    The Trick:
    I find it so difficult to understand the code and comments here. Is there a newbie-friendly thread regarding multithreading stuff in VB6. I'd really like to learn and use. I know it involves some basic(maybe advanced?) knowledge of COM, and I have read some articles from MSDN about it, but still I am having trouble here.
    I don't understand why did you say COM. I you want to use the threads you unnecessarily use COM.
    Newbir-friendly? Look at this:
    http://www.vbforums.com/showthread.p...-of-Native-DLL
    http://www.vbforums.com/showthread.p...n-Standart-EXE
    In the first example you can debug the threads in IDE, but you need to use the additional DLL. Second example involves the simple stuff like find prime numbers in new thread etc. Unfortunately in this case the treads don't work in IDE (all examples work in Main thread), after compiling they work in the new thread.
    Quote Originally Posted by bPrice View Post
    I understand that to fully know how it works takes more time but right now I just hope to find something that I can use right away. My current problem is to send HTTP requests asynchronously, wait for each response, and process them after all response are received. This will accelerate my program a bit I guess.
    For asynchronously request you unnecessarily use threads, you can use XMLHTTP and asynchronous

  12. #12
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    That's not newbie-friendly at all...
    Last edited by bPrice; Jan 15th, 2016 at 11:59 PM.

  13. #13
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Olaf, I read another thread where you commented. Thanks for all the example code there. Still:

    The simplest way to create Thread-STAs in VB6 is still per ActiveX-Exe,
    or per DirectCOM.dll (harder) - or with the RC5-cThreadHandler-Class (easier again).
    I'd very much like to have an example of threading related classes in RC5... At present, I am trying my best to experiment with ActiveX-Exe, but I am not sure whether it will be easy for deployment.
    Last edited by bPrice; Jan 16th, 2016 at 12:08 AM.

  14. #14
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by bPrice View Post
    That's not newbie-friendly at all...
    If it isn't for newbie then i can't help anything:
    Code:
    Private Sub cmdNewWnd_Click()
        Dim hThread As Long
        Dim capt    As String
        Dim lpCapt  As Long
        
        capt = InputBox("Window title", "")
        lpCapt = SysAllocString(StrPtr(capt))
        
        hThread = vbCreateThread(0, 0, AddressOf NewThreadProc, lpCapt, 0, 0)
        
        CloseHandle hThread
        
    End Sub
    
    Public Function NewThreadProc(ByVal value As String) As Long
        Dim frm As Form
        
        Set frm = New frmTest1
        
        frm.Caption = value
        frm.Show vbModal
        
    End Function

  15. #15
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by The trick View Post
    If it isn't for newbie then i can't help anything:
    Code:
    Private Sub cmdNewWnd_Click()
        Dim hThread As Long
        Dim capt    As String
        Dim lpCapt  As Long
        
        capt = InputBox("Window title", "")
        lpCapt = SysAllocString(StrPtr(capt))
        
        hThread = vbCreateThread(0, 0, AddressOf NewThreadProc, lpCapt, 0, 0)
        
        CloseHandle hThread
        
    End Sub
    
    Public Function NewThreadProc(ByVal value As String) As Long
        Dim frm As Form
        
        Set frm = New frmTest1
        
        frm.Caption = value
        frm.Show vbModal
        
    End Function
    Wow it seems quite handy indeed, if it's only for making use. Usually I will have to at least understand a bit how it works and that's when all the APIs and C-like datatypes(sometimes assemblies) ... seem formidable.

    VbCreateThread is from here right? I'll try again ...

  16. #16

  17. #17

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by bPrice View Post
    I checked classes in RC5 and got:

    Code:
    cThreadHandler
    cThreadInit
    cThreadMethods
    cThreadProxy
    Only the first one (cThreadHandler) is needed in the "higher-level"-RC5-Threading-support
    (the others are helper-Classes only, which you don't come into contact with "on the outside").

    Quote Originally Posted by bPrice View Post
    seems they work with: cRegFree
    'The DirectCOM methods are also incorporated in RC5?
    Yes, once you have instantiated (kind of "bootstrapped") the New_c (of type cConstructor)
    regfree per direct API-call using a Declare-Statement for DirectCOM.dll (GetInstancEx), you
    can then use New_c.Regfree to instantiate all kind of "other COM-Dlls" more conveniently:
    - either in the current Thread per New_C.Regfree.GetInstanceEx -
    - or on an entirely new Thread per New_c.Regfree.ThreadObjectCreate

    Quote Originally Posted by bPrice View Post
    An easy example will be much appreciated!!
    Posted one finally into the CodeBank here:
    http://www.vbforums.com/showthread.p...-ThreadHandler

    Maybe you found it already.

    Olaf

  18. #18

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by LaVolpe View Post
    Olaf, also a bit interested for a specific purpose. Any suggestions welcomed.

    Scenario: image format. Manually parsing file to extract animation frames, frames composed to an image-strip. The image strip is basically a 32bpp bitmap data, bytes only, ( (FrameWidth* frameCount) x FrameHeight) and will be contained in COM stream

    I imagine myself using threading to create this image-strip in the background. The COM stream is created on the main thread but populated from the background thread. The COM stream is not guaranteed to be accessible by hGlobal, may be virtual via IStorage. A timer on the main thread can check for a flag set by the background thread when task is completed.

    Are COM objects shareable between the main thread and background thread? Any tips on GDI+ usage between threads and sharing of GDI+ object handles?
    Are you still interested in using DirectCOM.dll to solve this -
    or did you already managed a solution (using Tricks stuff)?

    As far as Stream-Instances are concerned, these should be threadsafe, even when passed
    (per Pointer) among threaded STAs - just ensure proper synchronization on your own -
    not so sure about GDI+ Handles and methods about their thread-safety (when passed
    as Pointers between STAs)... I'd create a basic "GDI+ environment" within *each* Threads
    STA to be on the safe side - and use the GDI+ calls within that STA only on GDI+ Handles
    created within said STA - that should work safely.

    Olaf

  19. #19
    New Member
    Join Date
    Feb 2020
    Posts
    2

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Hi Olaf,

    First I have to say, I'm a big fan of your work. I have been using Cairo and RC5 since it was called dhRichClient3. Thank you for that.

    Now my question about this subject: I spent a lot of time trying to figure out why my code was not working and finally I think I found the problem. I was trying to pass String variables (several of them actually) between the thread and the main application inside of the ThreadInitDirectCOM type. And I noticed that as soon as I add string variables there, the thread does not gets loaded.

    1st question: Can I use string variables inside of Type ThreadInitDirectCOM ?
    If not - can I pass my strings as byte array and is there a limitation on the size?
    (I'm not going to pass anything crazy like megabytes of data, just a couple of kilobytes at the most)

    And 2nd question: Is the Reserved(0 To 127) As Long array reserved for some internal use? Or was it just a part of example and can it be deleted?

    Thanks.

  20. #20

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    To your second question first...
    The current (0 to 127) "Reserved-Space" Long-Array is perhaps a bit generous (and currently not used fully),
    but the entry needs to exist...

    To your other question, regarding "BSTR-types in the shared Mem-Area TypeDef"...

    These are possible, but since BSTRs are "RefTypes", they'll allocate memory sidewards into their "Pointer-Slot" within the UDT.

    And this Operation has to be made threadsafe, by protecting the read-and write-ops with:
    - either Mutexes o.a. (when the shared-memory-area was created for cross-process-access)
    - or as in our case via CriticalSections (where we share the mem-area InProcess-cross-thread)

    Below comes replacement code, which demonstrates that:

    Into the Exe-Project-Class cThreadWrapper:
    Code:
    Option Explicit 'it's a good idea, to wrap your Remote-Threads in its own Wrapper-Class
     
    Private Type ThreadInitDirectCOM
      Param As Long 'User-Param (given into the ThreadMain-Method of the COM-Dll)
      hThread As Long 'filled from Thread (instantly, after STARTCOMOBJECT() returns)
      ThreadID As Long 'filled from Thread (if fully initialized, some msec after STARTCOMOBJECT())
      Reserved(0 To 127) As Long
      
      'userdefined Params can be placed here...
      aCS(0 To 7) As Long 'CriticalSection-range in a size sufficient also for 64Bit-API-calls (the mainthread should init this)
     
      FPS As String 'will reflect the current FPS of the Remote-Thread
      CancelThread As Boolean 'will be used to signalize Thread-Cancelling to the Remote-Thread
    End Type
    
    'this is the call which ensures a new STA with a regfree loaded AX-Dll-Class-Instance in it...
    Private Declare Function STARTCOMOBJECT Lib "DirectCom" (FName As String, ClassName As String, TI As Any) As Long
    
    'and below just some accompanying APIs we use here in the wrapper-class, to handle the Memory-Sharing and the Closing of the Remote-Thread
    Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Arr() As Any) As Long
    Private Declare Sub Sleep Lib "kernel32" (ByVal mSec As Long)
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    
    Private Declare Sub InitializeCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    Private Declare Sub DeleteCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    Private Declare Sub EnterCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    Private Declare Sub LeaveCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    
    Private TI() As ThreadInitDirectCOM 'will host the TI-allocation, which we create here in the Main-Thread
    
    Private Sub Class_Initialize() 'prepare the TI-Array (which has only a single "Index-Slot" and is shared with the Remote-Thread)
      ReDim TI(0 To 0) 'we allocate the SharedMem-Array here in the Main-Thread
            TI(0).Param = ArrPtr(TI) 'the Param-Member is, what gets passed into the ThreadMain-Function of the Remote-Class
      InitializeCriticalSection TI(0).aCS(0) 'init the Critical Section on the allocation .aCS
    End Sub
    
    Public Sub StartThread()
      STARTCOMOBJECT App.Path & "\Bin\ThreadLib.dll", "cThread", ByVal VarPtr(TI(0))  'start the Thread along with the ThreadLib.dll-cThread-Class regfree
    End Sub
    
    Public Property Get ThreadID() As Long
      ThreadID = TI(0).ThreadID '<- the .ThreadID-member of TI gets filled in the upstarting Remote-Thread
    End Property
    
    Public Property Get FPS() As String
      EnterCriticalSection TI(0).aCS(0) 'BSTR-member-access has to be protected via CriticalSections (in Read, as well as in Write-Direction)
        FPS = TI(0).FPS '<- the .FPS-StringMember of TI gets filled and updated in the Remote-Thread via Property-Let
      LeaveCriticalSection TI(0).aCS(0)
    End Property
    
    Private Sub Class_Terminate() 'this ensures, that the Remote-Thread-Class dies along with this Wrapper-Class
      TI(0).CancelThread = True 'signalize the Remote-Thread, that we want to close it
      Sleep 50 'give the Remote-Thread some time, after we signaled it to close itself (in the line above)
      CloseHandle TI(0).hThread 'just to avoid Handle-Leakage
      DeleteCriticalSection TI(0).aCS(0) 'delete the CriticalSection
    End Sub
    And this into the ThreadLib-Project-Class cThread:
    Code:
    Option Explicit
    
    Private Declare Sub BindArray Lib "kernel32" Alias "RtlMoveMemory" (PArr() As Any, ByVal pSrc&, Optional ByVal CB& = 4)
    Private Declare Sub ReleaseArray Lib "kernel32" Alias "RtlMoveMemory" (PArr() As Any, Optional pSrc& = 0, Optional ByVal CB& = 4)
    Private Declare Sub EnterCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    Private Declare Sub LeaveCriticalSection Lib "kernel32" (CS_20_or_32Byte As Any)
    
    Private Type ThreadInitDirectCOM
      Param As Long 'User-Param (given into the ThreadMain-Method of the COM-Dll)
      hThread As Long 'filled from Thread (instantly, after STARTCOMOBJECT() returns)
      ThreadID As Long 'filled from Thread (if fully initialized, some msec after STARTCOMOBJECT())
      Reserved(0 To 127) As Long
      
      'userdefined Params can be placed here...
      aCS(0 To 7) As Long 'CriticalSection-range in a size sufficient also for 64Bit-API-calls (the mainthread should init this)
     
      FPS As String 'will reflect the current FPS of the Remote-Thread
      CancelThread As Boolean 'will be used to signalize Thread-Cancelling to the Remote-Thread
    End Type
    
    
    Private TI() As ThreadInitDirectCOM
    
    Public Function ThreadMain(ByVal Param As Long) As Long
      BindArray TI, Param  'span TI virtually over the same Memory as occupied by the TI-Array which was allocated in the Main-Threads ThreadWrapper-Class
        Set fThread.Thread = Me 'hand a reference of this Class-Instance over into the Thread-Form too
            fThread.Caption = "ThreadID: " & App.ThreadID 'update the ThreadForms Caption with the ThreadID of this Thread
            fThread.Show vbModal 'show the ThreadForm modally
        Set fThread.Thread = Nothing
      ReleaseArray TI 'avoid double-freeing (since the TI-Array is already freed in the MainThreads ThreadWrapper-Instance)
    End Function
    
    Friend Property Let FPS(ByVal RHS As String)  'a Let-Property for the Write-Direction (Information, updated from this Thread here)
      EnterCriticalSection TI(0).aCS(0) 'BSTR-member-access has to be protected via CriticalSections (in Read, as well as in Write-Direction)
        TI(0).FPS = RHS 'now we can update the shared-memory BSTR-Member (to give an example, how we transport Info from here into the Main-Thread)
      LeaveCriticalSection TI(0).aCS(0)
    End Property
    
    Friend Property Get Cancelled() As Boolean 'a Get-Property for the Read-Direction on the Shared-Memory-Array (reading a member which is updated from the Main-Thread)
      Cancelled = TI(0).CancelThread 'so, here's the opposite to FPS (we access the CancelThread-Member, to detect when the Main-Thread wants us to close)
    End Property
    HTH

    Olaf

  21. #21
    New Member
    Join Date
    Feb 2020
    Posts
    2

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Thank you so much, Olaf.
    I will use your code.

  22. #22

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: VB6 Threading, using the small DirectCOM.dll-HelperLib

    Quote Originally Posted by NetChain View Post
    Thank you so much, Olaf.
    I will use your code.
    Ok, though in case you "expand on the little demo" a bit, I'd suggest
    to place the (currently identical, but "defined separately") SharedUDT-Definition -
    in its own *.bas module (e.g. named: modSharedTypes.bas, making the Type Public there)...

    Then place the same "file-reference" to this new 'modSharedTypes.bas' module
    in both projects (the Main-StdExe- as well as the ThreadHelper-Dll-Project),
    so that in case of UDT-changes, you wont have to "synchronize them manually" in the other Project.

    Olaf

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width