Skip to content

Latest commit

 

History

History
134 lines (100 loc) · 3.9 KB

File metadata and controls

134 lines (100 loc) · 3.9 KB
title Enhanced Pointer Functionality
parent Language Syntax
nav_order 10
permalink /Features/Language/Pointers

Enhanced Pointer Functionality

twinBASIC provides several enhancements for working with pointers.

ByVal Nothing

While not strictly new syntax, twinBASIC also adds support for ByVal Nothing, to override a ByRef <interface> argument and pass a null pointer there.

ByVal vbNullPtr

Allows passing null pointers to UDT members of APIs/interfaces. The equivalent behavior in VBx is to declare them As Any and then pass ByVal 0 at call sites.

Example

Type Foo
   bar As Long
End Type
Public Declare PtrSafe Function MyFunc Lib "MyDLL" (pFoo As Foo) As Long

Private Sub CallMyFunc()
    Dim ret As Long = MyFunc(ByVal vbNullPtr)
End Sub

Substitute Pointers for UDTs

More generally, in both APIs and local methods, any argument taking a user-defined type can instead be passed a ByVal LongPtr, with the new special constant vbNullPtr used for a null pointer:

Public Declare PtrSafe Function CreateFileW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As LongPtr) As LongPtr

hFile = CreateFileW(StrPtr("name"), 0, 0, ByVal vbNullPtr, '...)
'---or---
Dim pSec As SECURITY_ATTRIBUTES
Dim lPtr As LongPtr = VarPtr(pSec)
hFile = CreateFileW(StrPtr("name"), 0, 0, ByVal lPtr, '...)

CType(Of <type>)

The CType(Of <type>) operator specifies an explicit intent to cast one type to another. This can be used for casting LongPtr (or Long on 32bit/LongLong on 64bit) to a custom user-defined type, with or without making a copy of it, depending on the usage. This allows not just for casting directly without a CopyMemory call, but also, setting the members of a UDT represented only by a pointer, without copying memory back and forth.

Example

Consider the following UDTs:

Private Type foo
    a As Long
    b As Long
    pfizz As LongPtr 'A pointer to a variable of type fizz
End Type
Private Type bar
    pfoo As LongPtr 'A pointer to a variable of type foo
End Type
Private Type fizz
    c As Long
End Type

The following code examples work to manipulate the pointers:

Sub call1()
    Dim f As foo
    test1 VarPtr(f)
    Debug.Print f.a, f.b
End Sub

Sub test1(ByVal ptr As LongPtr)
    With CType(Of foo)(ptr)
        .a = 1
        .b = 2
    End With
End Sub

This will print 1 2.

Sub call2()
    Dim f As foo, b As bar
    b.pfoo = VarPtr(f)
    test2 b
    Debug.Print f.a, f.b
End Sub

Sub test2(b As bar)
    With CType(Of foo)(b.pfoo)
        .a = 3
        .b = 4
    End With
End Sub

This will print 3 4.

Sub call3()
    Dim f As foo, b As bar, z As fizz
    f.pfizz = VarPtr(z)
    b.pfoo = VarPtr(f)
    test3 b
    Debug.Print z.c
End Sub

Sub test3(b As bar)
    CType(Of fizz)(CType(Of foo)(b.pfoo).pfizz).c = 4
End Sub

This will print 4. Free standing use and nesting is also allowed; the above will print 4. While the examples here are local code only, this is particularly useful for APIs, where you're forced to work with pointers extensively.

Len/LenB(Of <type>) Support

The classic Len and LenB functions can now be used to directly get the length/size of a type, both intrinsic and user-defined, without needing have declared a variable of that type. For instance, to know the pointer size, you can use LenB(Of LongPtr).

Improvements to AddressOf

AddressOf can be now be used on class/form/usercontrol members, including from outside the class by specifying the instance. Also, no need for FARPROC-type functions, you can use it like Ptr = AddressOf Func. So if you have class CFoo with member function bar, the following is valid:

Dim foo1 As New CFoo
Dim lpfn As LongPtr = AddressOf foo1.bar