OpenClass - and Powerbasic Objects revisited

Started by Theo Gottwald, January 17, 2026, 10:17:51 AM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

Theo Gottwald

For many Year i used the simple OpenClass-Macro like this:

    MACRO OpenClass(P1,P2,P3) = P1 = CLASS P3:POKE DWORD, VARPTR(P1),P2: P1.AddRef
    ' Beispiel: OpenClass(E1,T01,"ThreadP")


After searching for the reason of some crashes i asked AI and the answer was:
"You are using it wrong!!"

And i got this safe Implementation:
' --- needed for pointer sanity checks (kernel32) ---
DECLARE FUNCTION IsBadReadPtr LIB "kernel32.dll" (BYVAL lp AS DWORD, BYVAL cb AS DWORD) AS LONG

' Returns 1 if p looks like a valid COM interface pointer (readable + readable vtbl)
FUNCTION PB_IsValidIFacePtr(BYVAL p AS DWORD) AS LONG
    LOCAL pVtbl AS DWORD

    FUNCTION = 0
    IF p = 0 THEN EXIT FUNCTION
    IF IsBadReadPtr(BYVAL p, 4) THEN EXIT FUNCTION

    pVtbl = PEEK(DWORD, p)
    IF pVtbl = 0 THEN EXIT FUNCTION
    IF IsBadReadPtr(BYVAL pVtbl, 4) THEN EXIT FUNCTION

    FUNCTION = 1
END FUNCTION

' P1 - Interfacevariable, P2 - Object pointer (Interface ptr), P3 - "ClassName"
' Safe: avoids crash on invalid pointer, avoids leaks
MACRO OpenClass(P1, P2, P3)
    ' Force PB to resolve class symbol; immediately release dummy instance to avoid leaks
    P1 = CLASS P3
    P1 = NOTHING

    IF PB_IsValidIFacePtr(P2) THEN
        POKE DWORD, VARPTR(P1), P2
        P1.AddRef
    END IF
END MACRO
         

I remember that i had problems in the past with the original Implementation but i never found where the problem arrived from. And now in Age of Ki. It looks so easy to fix bugs that were there for years. And i never knew.

Theo Gottwald

#1
With PBXB64 you can do this also:


PBXB64 has a dedicated source-backed mechanism for that: INHERIT IPowerThread with a THREAD METHOD.

CLASS ThreadP
    INHERIT IPowerThread
    INSTANCE THREADPARAM AS LONG
    INSTANCE Counter AS LONG

    THREAD METHOD Run() AS LONG
        Counter = Counter + THREADPARAM
        METHOD = Counter
    END METHOD
END CLASS


Calling worker.Launch(1) starts Run on that instance. Inside Run, its instance variables—including Counter—are available normally. You do not need to construct a second object or overwrite its pointer.
If the worker must access a different existing class object, PBXB64 also has a typed parameter form:

INSTANCE THREADPARAM AS YourClass

Then launch it with worker.Launch(existingObject).

There is a [registered regression example for retaining that object during worker execution (line 15)](.../tests/pb/com_powerthread_internal_typed_object.pb:15).

Two distinctions matter:
- A method can access its own class's private variables; another class's private fields still require methods or properties.
- If multiple threads modify the same variables, you still need synchronization. AddRef protects lifetime, not concurrent access.
This is verified in the live source and registered examples; I haven't rerun those tests. Your OpenClass macro should therefore be replaced with this object-aware thread mechanism.

Easier it is to just use the XTHREAD CREATE( ....).