VB6 Threading, using the small DirectCOM.dll-HelperLib-VBForums
Results 1 to 18 of 18

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

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    2,662

    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 05:27 PM.

  2. #2

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Jun 2013
    Posts
    2,662

    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
    15,367

    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"

    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} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VB and DPI Tutorial} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

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

    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
    Fanatic Member The trick's Avatar
    Join Date
    Feb 2015
    Location
    Russia, Astrakhan
    Posts
    773

    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: 419
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
    15,367

    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"

    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} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VB and DPI Tutorial} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9
    Fanatic Member The trick's Avatar
    Join Date
    Feb 2015
    Location
    Russia, Astrakhan
    Posts
    773

    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
    Fanatic Member The trick's Avatar
    Join Date
    Feb 2015
    Location
    Russia, Astrakhan
    Posts
    773

    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
    Fanatic Member The trick's Avatar
    Join Date
    Feb 2015
    Location
    Russia, Astrakhan
    Posts
    773

    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
    2,662

    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
    2,662

    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

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

Survey posted by VBForums.