Results 1 to 8 of 8

Thread: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

  1. #1

    Thread Starter
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,098

    Thumbs up [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    Using twinBasic's ability to define interfaces in code I whipped up this simple Timer that implements the WinRT ThreadPoolTimer Class. The code is so much shorter and cleaner than its VB6 equivalent:

    cTimer.twin
    Code:
    [InterfaceId("34ED19FA-8384-4EB9-8209-FB5094EEEC35")]
    Interface TimerDestroyedHandler Extends IUnknown
        Sub Invoke(ByVal ThreadPoolTimer As IThreadPoolTimer)
    End Interface
    [InterfaceId("FAAEA667-FBEB-49CB-ADB2-71184C556E43")]
    Interface TimerElapsedHandler Extends IUnknown
        Sub Invoke(ByVal ThreadPoolTimer As IThreadPoolTimer)
    End Interface
    [InterfaceId("594EBE78-55EA-4A88-A50D-3402AE1F9CF2")]
    Interface IThreadPoolTimer Extends IInspectable
        Property Get Period() As Currency
        Property Get Delay() As Currency
        [PreserveSig]
        Function Cancel() As HRESULTS
    End Interface
    [InterfaceId("1A8A9D02-E482-461B-B8C7-8EFAD1CCE590")]
    Interface IThreadPoolTimerStatics Extends IInspectable
        [PreserveSig]
        Function CreatePeriodicTimer(ByVal handler As TimerElapsedHandler, ByVal period As Currency, timer As IThreadPoolTimer) As HRESULTS
        [PreserveSig]
        Function CreateTimer(ByVal handler As TimerElapsedHandler, ByVal delay As Currency, timer As IThreadPoolTimer) As HRESULTS
        [PreserveSig]
        Function CreatePeriodicTimerWithCompletion(ByVal handler As TimerElapsedHandler, ByVal period As Currency, ByVal destroyed As TimerDestroyedHandler, timer As IThreadPoolTimer) As HRESULTS
        [PreserveSig]
        Function CreateTimerWithCompletion(ByVal handler As TimerElapsedHandler, ByVal delay As Currency, ByVal destroyed As TimerDestroyedHandler, timer As IThreadPoolTimer) As HRESULTS
    End Interface
    
    [PredeclaredId]
    Class cTimer
        Private DeclareWide PtrSafe Function WindowsCreateString Lib "combase" (ByVal sourceString As String, ByVal length As Long, hString As LongPtr) As HRESULTS
    
        Private ThreadPoolTimerStatics As IThreadPoolTimerStatics
        
        Private Sub Class_Initialize()
            Dim hString As LongPtr, IID_IThreadPoolTimerStatics As UUID
            Const sWindowsSystemThreadingThreadPoolTimer As String = "Windows.System.Threading.ThreadPoolTimer"
            Const sIID_IThreadPoolTimerStatics As String = "{1A8A9D02-E482-461B-B8C7-8EFAD1CCE590}"
            If WindowsCreateString(sWindowsSystemThreadingThreadPoolTimer, Len(sWindowsSystemThreadingThreadPoolTimer), hString) = S_OK Then
                If IIDFromString(sIID_IThreadPoolTimerStatics, IID_IThreadPoolTimerStatics) = S_OK Then
                    If RoGetActivationFactory(hString, IID_IThreadPoolTimerStatics, ThreadPoolTimerStatics) = S_OK Then
                        Debug.Print "ThreadPoolTimerStatics created"
                    End If
                End If
                WindowsDeleteString hString
            End If
        End Sub
        
        Friend Function CreatePeriodicTimer(handler As TimerElapsedHandler, period As Currency) As IThreadPoolTimer
            ThreadPoolTimerStatics.CreatePeriodicTimer (handler, period, CreatePeriodicTimer)
        End Function
    End Class
    Form1.twin
    Code:
    [Description("")]
    [FormDesignerId("D0EA899E-511B-41B0-BFC7-23DFA02341E4")]
    [PredeclaredId]
    Class Form1
        Implements TimerElapsedHandler
        
        Private ThreadPoolTimer As IThreadPoolTimer, lCount As Long
    
        Private Sub TimerElapsedHandler_Invoke(ByVal ThreadPoolTimer As IThreadPoolTimer)
            lCount = lCount + 1
            txtTimer = txtTimer & lCount & " - " & ThreadPoolTimer.Period & "ms" & vbNewLine
            If lCount = 5 Then ThreadPoolTimer.Cancel: lCount = 0: txtTimer = txtTimer & "Canceled": cmdStartTimer.Enabled = True
        End Sub
        
        Private Sub cmdStartTimer_Click()
            txtTimer = vbNullString: cmdStartTimer.Enabled = False
            Set ThreadPoolTimer = cTimer.CreatePeriodicTimer(Me, 500)
        End Sub
    End Class
    Name:  ThreadPoolTimer.png
Views: 221
Size:  4.9 KB

    I can't upload the project file as it exceeds the size limit (probably due to Fafalone's WinDevLib, haha), but as my first twinBasic project, I was pleasantly surprised to see how well it performs. Cool stuff!

  2. #2
    PowerPoster yereverluvinuncleber's Avatar
    Join Date
    Feb 2014
    Location
    Norfolk UK (inbred)
    Posts
    2,615

    Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    Hmmmm, simple. A new definition of simple for me.
    https://github.com/yereverluvinunclebert

    Skillset: VMS,DOS,Windows Sysadmin from 1985, fault-tolerance, VaxCluster, Alpha,Sparc. DCL,QB,VBDOS- VB6,.NET, PHP,NODE.JS, Graphic Design, Project Manager, CMS, Quad Electronics. classic cars & m'bikes. Artist in water & oils. Historian.

    By the power invested in me, all the threads I start are battle free zones - no arguing about the benefits of VB6 over .NET here please. Happiness must reign.

  3. #3

    Thread Starter
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,098

    Talking Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    Haha, then you don't want to see the VB6 equivalent of this Timer class. It gets exponentially more complicated due to the missing ability to define interfaces in code.

    Theoretically you could make it the same in VB6 if you took those interface definitions, put them in an IDL file, compile it into a TypeLib and reference that in VB6. Then it would be identical. But without a TypeLib it gets really messy with low level vtable calls and light-weight objects emulated in a BAS module.

  4. #4
    Hyperactive Member -Franky-'s Avatar
    Join Date
    Dec 2022
    Location
    Bremen Germany
    Posts
    296

    Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    Quote Originally Posted by yereverluvinuncleber View Post
    Hmmmm, simple. A new definition of simple for me.
    That would be the same path I would take in .NET. Up to NET 4.8.x you can at least set a reference to Windows.winmd to use WinRT. From NET5 onwards you have to write the interfaces yourself, like VanGoghGaming does for TwinBasic.

  5. #5
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    6,336

    Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    I'm still hoping there's some way to add the ability to use WinRT natively in tB, without .NET-ifying the language. There's C++/WinRT so maybe not all hope is lost...

    Seems necessary when Microsoft is locking up so many new features with WinRT... Instead of just a friendly wrapper class wrapper, there's no publicly documented underlying standard API set or COM interfaces for things like toast notifications and OCR.


    ---

    Btw great job on the project VanGoghGaming, nice to see somebody besides me posting new tB-only CodeBank projects. Though I still say you should abolish the evil Currency unless you're actually working with, you know, Currencies, and use tB's LongLong and change the 500 to 5000000 so there's no hard to catch magic behind the scenes stuff.

    Also as a more practical issue... It doesn't matter for this project but in the future, if you have UDTs with INT64 types... Things might not work, especially under x64, if you use Currency because it's not a 'true' 8-byte type, it's a struct of 2x4 byte members that VB6 (and tB for compatibility) presents as an 8-byte type but treats it under the hood as 2x4 bytes-- which means it doesn't trigger 8-byte packing alignment in UDTs.

    This is a major gotcha for x64 porting... It's rare for it to matter in 32bit, but common in 64bit. If you have

    Code:
    Type foo
        a As Long
        b As Currency
    End Type
    Where you substituted Currency for UINT64... A Windows API expecting standard x64 packing alignment will throw an error there, because with Currency it's a 12-byte contiguous struct. But a real UINT64, if you use LongLong, as a true 8-byte type, it's a 16-byte struct with 4 bytes of hidden padding after the first Long because 8-byte vars have to appear at 8-byte intervals.

    It was super petty and obnoxious for Microsoft to only allow LongLong in 64bit VBA7, but tB has no such limit, so use LongLong

    PPS- LARGE_INTEGER should be QuadPart As LongLong in tB instead of 2x4 bytes, because in the Windows API, it's actually a union, and if any union alternate is 8 bytes, it triggers 8 byte packing alignment. Again so rare to matter in 32bit... But man would you be chasing your tail for hours trying to figure out why some API isn't working in 64bit if you didn't know that. It's extremely common.


    Tl:;Dr -- LongLong, not Currency!! Lol

  6. #6

    Thread Starter
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,098

    Wink Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    LoL, so much Currency hate in one of the few cases where it actually fits like a glove! The "TimeSpan" structure looks like it was created specifically for Currency since a single tick represents one hundred nanoseconds and there are 10,000 ticks in a millisecond.

    It reminds me of one of the threads that spawn regularly where someone asks how to exit multiple "For" loops and people go out of their way to devise complicated solutions just to avoid a simple "GoTo"!

  7. #7
    PowerPoster
    Join Date
    Jan 2020
    Posts
    4,464

    Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    There are some callbacks in this multithreading that you have to process immediately, and if you need 500 milliseconds or two seconds to complete that task, it may crash.

  8. #8

    Thread Starter
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,098

    Re: [twinBASIC] - Simple cTimer example implementing the WinRT ThreadPoolTimer Class

    Have you actually tried that? I bet it won't crash no mater how long your main thread is busy.

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