Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions docs/Reference/Core/AddressOf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: AddressOf
parent: Operators
grand_parent: Reference Section
permalink: /tB/Core/AddressOf
---
# AddressOf operator
{: .no_toc }

A unary operator that returns a function-pointer reference to its operand.

Syntax:
> **AddressOf** *procedurename*
> **AddressOf** *instance*.*procedurename* *(twinBASIC)*

*procedurename*
: The name of a [**Sub**](Sub), [**Function**](Function), or [**Property**](Property) procedure whose address is taken.

*instance*
: *optional* (twinBASIC) An object reference whose member *procedurename* is targeted. The resulting pointer is bound to *instance*, so calling through it invokes the method on that specific object.

When a procedure name appears in an argument list, normally the procedure is *called* and the procedure's return value is passed. **AddressOf** suppresses the call and substitutes the procedure's address instead. The most common use is to install a callback in a Windows API — the API then invokes the procedure from outside your code, in a process known as a *callback*.

The value **AddressOf** produces is bit-compatible with **LongPtr**, so it can be passed wherever a function pointer is expected — including legacy [**Declare**](Declare) parameters typed **As Long** or **As LongPtr**. When the destination type is a [**Delegate**](Delegate), the compiler additionally checks that the operand's signature matches the delegate's.

In classic VBA, *procedurename* must name a procedure in a standard [**Module**](Module) of the current project; the destination parameter must be typed **As Long**; and the resulting pointer can only be invoked by code outside Basic (e.g. a DLL). twinBASIC lifts each of these restrictions — see [twinBASIC enhancements](#twinbasic-enhancements) below.

> [!NOTE]
> Errors raised inside a callback cannot propagate back to the foreign caller — the API runs outside your project's error-handling chain. Place `On Error Resume Next` (or an explicit handler) at the top of any procedure used as an **AddressOf** target.

### twinBASIC enhancements

- **Indirect calls back through Basic.** A delegate variable holding an **AddressOf** value can be called directly: `Dim op As Operation = AddressOf Add: r = op(5, 6)`. Classic VBA can pass such pointers between procedures but cannot invoke through them inside Basic. See [**Delegate**](Delegate).
- **Class, form, and user-control members.** **AddressOf** accepts methods declared on a class, form, or user-control. Take a pointer to an instance method by qualifying the name with the object reference: `AddressOf myInstance.MyMethod`. The resulting pointer remembers the instance — calling through it dispatches to that object.
- **CDecl callbacks.** Mark both the target procedure and the matching [**Delegate**](Delegate) (or [**Declare**](Declare) parameter) with **CDecl** to model `cdecl` callbacks. Classic VBA's **AddressOf** is hard-wired to `__stdcall`. See [API Declarations](../../Features/Advanced/API-Declarations#cdecl-callbacks).
- **No `FARPROC` shim needed.** Assigning a function pointer to a local variable is direct — `Dim lpfn As LongPtr = AddressOf MyFunc` — without writing an intermediate forwarding procedure.

### Example

Calling through a typed delegate, inside Basic:

```tb
Private Delegate Function Operation (ByVal A As Long, ByVal B As Long) As Long

Public Function Addition(ByVal A As Long, ByVal B As Long) As Long
Return A + B
End Function

Private Sub Demo()
Dim op As Operation = AddressOf Addition
Debug.Print op(5, 6) ' 11
End Sub
```

Installing a callback in a Win32 API. `EnumWindows` invokes *EnumProc* once per top-level window:

```tb
Public Declare PtrSafe Function EnumWindows Lib "user32" ( _
ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long

Public Function EnumProc(ByVal hwnd As LongPtr, ByVal lParam As LongPtr) As Long
On Error Resume Next
Debug.Print hwnd
EnumProc = 1 ' Continue enumeration.
End Function

Public Sub ListTopLevelWindows()
EnumWindows AddressOf EnumProc, 0
End Sub
```

Taking a pointer to an instance method by qualifying with the object reference:

```tb
Class CFoo
Public Sub Bar()
Debug.Print "Bar on instance"
End Sub
End Class

Public Sub Demo()
Dim foo1 As New CFoo
Dim lpfn As LongPtr = AddressOf foo1.Bar
End Sub
```

### See Also

- [**Delegate** statement](Delegate)
- [**Declare** statement](Declare)
- [Delegate Types](../../Features/Language/Delegates)
- [Enhanced Pointer Functionality](../../Features/Language/Pointers)
- [API Declarations](../../Features/Advanced/API-Declarations)
- [Operators](../../Reference/Operators)

{% include VBA-Attribution.md %}
61 changes: 61 additions & 0 deletions docs/Reference/Core/Alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
title: Alias
parent: Statements
permalink: /tB/Core/Alias
---
# Alias
{: .no_toc }

Declares an alternative name for an intrinsic type, user-defined [**Type**](Type), [**Interface**](Interface), or another **Alias**. The alias and the original type are interchangeable — assigning between them is not a type mismatch. Comparable to `typedef` in C/C++.

> [!NOTE]
> The **Alias** statement is a twinBASIC extension. It has no equivalent in classic VBA, where the only use of the **Alias** keyword is to name a DLL entry point in a [**Declare**](Declare) statement.

Syntax:
> [ **Public** \| **Private** ] **Alias** *aliasname* **As** *type*

**Public**
: *optional* The alias is exported to the type library of an ActiveX DLL or control, so consumers in other projects see *aliasname* itself.

**Private**
: *optional* The alias is visible only within the project. Usages of a **Private** alias are replaced with the underlying *type* during compilation, so *aliasname* never appears in the project's type library.

*aliasname*
: The name of the alias. Must be a valid twinBASIC identifier.

*type*
: The original type. May be an intrinsic type, a user-defined [**Type**](Type), an [**Interface**](Interface), or another **Alias**.

**Alias** statements are valid only in `.twin` source files (not legacy `.bas` or `.cls` files), and must appear at file scope — outside of [**Module**](Module) and [**Class**](Class) blocks, alongside [**Interface**](Interface) and [**CoClass**](CoClass) declarations.

### Example

Aliasing intrinsic types and a user-defined type:

```tb
Public Type POINT
x As Long
y As Long
End Type

Public Alias POINTAPI As POINT

Public Alias CBoolean As Byte

Public Alias KAFFINITY As LongPtr
```

A variable declared with the alias and a variable declared with the original type are interchangeable:

```tb
Dim p As POINT
Dim q As POINTAPI
p = q ' OK — no type mismatch.
```

### See Also

- [**Type** statement](Type)
- [**Interface** statement](Interface)
- [**CoClass** statement](CoClass)
- [Alias Types](../../Features/Language/Alias-Types)
35 changes: 31 additions & 4 deletions docs/Reference/Core/Class.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Used to define a class. Classes are templates from which objects are created --
Syntax:

> [ *attributes* ]
> **Class** *name*
> [ **Public** \| **Private** ] **Class** *name* [ **(** **Of** *typevars* **)** ]
>     [ **Inherits** *baseclass* ]
>     [ *classmember* ]
>     [ *classmember* ] ...
> **End Class**
Expand All @@ -22,14 +23,40 @@ Syntax:
: *optional* One or more of:
[ArrayBoundsChecks](Attributes#arrayboundschecks), [ClassId](Attributes#classid), [COMCreatable](Attributes#comcreatable), [CustomControl](Attributes#customcontrol), [Description](Attributes#description), [FloatingPointErrorChecks](Attributes#floatingpointerrorchecks), [FormDesignerId](Attributes#formdesignerid), [Hidden](Attributes#hidden), [IntegerOverflowChecks](Attributes#integeroverflowchecks), [PredeclaredID](Attributes#predeclaredid)

**Public**
: *optional* (twinBASIC) In an ActiveX project, marks the class as exported into the type library so that consumers in other projects can create and use it.

**Private**
: *optional* (twinBASIC) In an ActiveX project, withholds the class from the type library: it remains usable within the project but is not exported. The conventional pairing with [**CoClass**](CoClass) — a public **CoClass** as the consumer-visible contract paired with a `Private Class` as the hidden implementation — relies on this modifier.

*name*
: The identifier naming the class.

**Of** *typevars*
: *optional* (twinBASIC) One or more type variable names, separated by commas, that make the class a *generic class*. Each type variable can be referenced in member declarations as if it were a regular type. See [Generics](../../Features/Language/Generics).

**Inherits** *baseclass*
: *optional* (twinBASIC) Names a single base class whose **Public** and [**Protected**](Protected) members are inherited by *name*. The **Inherits** line, when present, must appear immediately after the **Class** header and before any other member. **Inherits** enables [**Overridable**](Sub) / **Overrides** members, explicit `*baseclass*.New(...)` chained constructor calls from inside `Sub New`, and **Protected** member visibility. See [Inheritance](../../Features/Language/Inheritance).

*classmember*
: *optional* Any of the following:

- [constant](../Gloss#constant) defined using [**Const**](Const),
- [variable](../Gloss#variable) defined using [**Public**](Public), [**Protected**](Protected), [**Private**](Private), and [**Dim**](Dim),
- [procedure](../Gloss#procedure) defined using [**Sub**](Sub), [**Function**](Function) and [**Property**](Property),
- [user-defined type (UDTs)](../Gloss#user-defined-type) defined using [**Type**](Type).
- [variable](../Gloss#variable) defined using [**Public**](Public), [**Protected**](Protected), [**Private**](Private), or [**Dim**](Dim),
- [procedure](../Gloss#procedure) defined using [**Sub**](Sub), [**Function**](Function), or [**Property**](Property) — including the special instance constructor `Sub New(`*args*`)`, which the runtime invokes when the class is created with [**New**](New),
- [user-defined type (UDTs)](../Gloss#user-defined-type) defined using [**Type**](Type),
- (twinBASIC) [**Implements**](Implements) clauses, listing interfaces or classes whose members this class provides bodies for.

In `.twin` files, a **Class** block may share a file with [**Interface**](Interface), [**CoClass**](CoClass), and [**Alias**](Alias) declarations (which appear *before* the **Class** block) and with a [**Module**](Module) block. In legacy `.cls` files the class is implicit and the **Class**/**End Class** keywords are not written.

### See Also

- [**Module** statement](Module)
- [**Interface** statement](Interface)
- [**CoClass** statement](CoClass)
- [**Implements** statement](Implements)
- [**Protected** statement](Protected)
- [**New** statement](New)
- [Inheritance](../../Features/Language/Inheritance)
- [Generics](../../Features/Language/Generics)

2 changes: 1 addition & 1 deletion docs/Reference/Core/Const.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Syntax:

*type*

: *optional* The data type of the constant; may be Byte, Boolean, Integer, Long, Currency, Single, Double, Decimal (not currently supported), Date, String, or Variant. Use a separate **As** *type* clause for each constant being declared.
: *optional* The data type of the constant; may be Byte, Boolean, Integer, Long, Currency, Single, Double, Decimal, Date, String, or Variant. Use a separate **As** *type* clause for each constant being declared.

*expression*

Expand Down
3 changes: 3 additions & 0 deletions docs/Reference/Core/Continue.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ While

: Used within a [While](While-Wend) loop

> [!NOTE]
> **Continue** is a twinBASIC extension. Classic VBA has no skip-iteration form for any loop construct — the closest equivalent is a forward [**GoTo**](GoTo) to a label placed just before the loop's terminator.

### Example

This example uses **Continue For** to skip processing of certain characters of the string.
Expand Down
9 changes: 6 additions & 3 deletions docs/Reference/Core/Declare.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Used at the module level to declare references to external procedures in a dynam

> [!NOTE]
>
> **Declare** statements with the PtrSafe keyword is the recommended syntax. **Declare** statements that include **PtrSafe** work correctly in twinBASIC and VBA version 7 development environment on both 32-bit and 64-bit platforms only after all data types in the **Declare** statement (parameters and return values) that need to store 64-bit quantities are updated to use LongLong for 64-bit integrals or LongPtr for pointers and handles. To ensure backwards compatibility with VBA version 6 and earlier, use the following construct:
> **Declare** statements with the PtrSafe keyword is the recommended syntax. **Declare** statements that include **PtrSafe** work correctly in twinBASIC and VBA version 7 development environment on both 32-bit and 64-bit platforms only after all data types in the **Declare** statement (parameters and return values) that need to store 64-bit quantities are updated to use LongLong for 64-bit integrals or LongPtr for pointers and handles.

To ensure backwards compatibility with VBA version 6 and earlier, use the following construct:

```tb
#If VBA7 Then
Expand All @@ -19,6 +21,7 @@ Declare PtrSafe Sub...
Declare Sub...
#EndIf
```

> [!NOTE]
>
> For code to run when built for 64-bit targets, all **Declare** statements must include the **PtrSafe** keyword, and all data types in the **Declare** statement (parameters and return values) that need to store 64-bit quantities must be updated to use **LongLong** for 64-bit integrals or **LongPtr** for pointers and handles.
Expand Down Expand Up @@ -65,7 +68,7 @@ Syntax:
: *optional* List of variables representing arguments that are passed to the procedure when it is called.

*type*
: *optional* Data type of the value returned by a **Function** procedure; may be Byte, Boolean, Integer, Long, LongLong, LongPtr, Currency, Single, Double, Decimal (not currently supported), Date, String (variable length only), Variant, a user-defined type (UDT), or an object type. **LongLong** is a valid declared type only on 64-bit platforms.
: *optional* Data type of the value returned by a **Function** procedure; may be Byte, Boolean, Integer, Long, LongLong, LongPtr, Currency, Single, Double, Decimal, Date, String (variable length only), Variant, a user-defined type (UDT), or an object type. **LongLong** is a valid declared type only on 64-bit platforms.

### arglist

Expand All @@ -92,7 +95,7 @@ Syntax: [ **Optional** ] [ **ByVal** \| **ByRef** ] [ **ParamArray** ] *varname*
: Required for array variables. Indicates that *varname* is an array.

*type*
: *optional* Data type of the argument passed to the procedure; may be **Byte**, **Boolean**, **Integer**, **Long**, **LongLong**, **LongPtr**, **Currency**, **Single**, **Double**, **Decimal** (not currently supported), **Date**, **String** (variable length only), **Object**, **Variant**, a user-defined type (UDT), or an object type. (**LongLong** is a valid declared type only on 64-bit platforms.)
: *optional* Data type of the argument passed to the procedure; may be **Byte**, **Boolean**, **Integer**, **Long**, **LongLong**, **LongPtr**, **Currency**, **Single**, **Double**, **Decimal**, **Date**, **String** (variable length only), **Object**, **Variant**, a user-defined type (UDT), or an object type. (**LongLong** is a valid declared type only on 64-bit platforms.)

If you include an argument list, the number and type of arguments are checked each time the procedure is called. The First sub in the following example takes one **Long** argument, wherease the Second sub takes no arguments:

Expand Down
2 changes: 1 addition & 1 deletion docs/Reference/Core/Deftype.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The statement name determines the data type:
| **DefCur** | **Currency** |
| **DefSng** | **Single** |
| **DefDbl** | **Double** |
| **DefDec** | **Decimal** (not currently supported) |
| **DefDec** | **Decimal** |
| **DefDate** | **Date** |
| **DefStr** | **String** |
| **DefObj** | **Object** |
Expand Down
102 changes: 102 additions & 0 deletions docs/Reference/Core/Delegate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Delegate
parent: Statements
permalink: /tB/Core/Delegate
---
# Delegate
{: .no_toc }

Declares a function-pointer type — a named signature that variables, parameters, and UDT members can hold a *reference* to a callable matching. A delegate value is bit-compatible with **LongPtr**, but adds compile-time signature checking when it is assigned, passed, or called.

> [!NOTE]
> The **Delegate** statement is a twinBASIC extension. In classic VBA, function pointers are untyped **LongPtr** values produced by **AddressOf** and called indirectly through hand-rolled mechanisms (`DispCallFunc`, `CallWindowProc` shims, etc.).

Syntax:
> [ **Public** \| **Private** ] **Delegate Function** *name* [ **CDecl** ] **(** [ *arglist* ] **)** **As** *type*

**Public**
: *optional* In an ActiveX project, exports the delegate type to the type library so consumers in other projects see *name*.

**Private**
: *optional* Withholds the delegate from the type library; usable only within the project.

*name*
: The identifier naming the delegate type. Must be a valid twinBASIC identifier.

**CDecl**
: *optional* Marks the delegate as using the C calling convention (`cdecl` — caller cleans the stack), used to model callbacks expected by C-runtime APIs such as `qsort`. The default is `stdcall`. See [API Declarations](../../Features/Advanced/API-Declarations#cdecl-callbacks).

*arglist*
: *optional* Parameter signature, written exactly as for a [**Sub**](Sub) or [**Function**](Function) — comma-separated `[ ByVal | ByRef ] [ Optional ] *varname* [ As *type* ]` parts.

*type*
: Return type of the delegate's signature.

After the declaration, *name* may be used wherever a type is allowed: to declare variables and parameters of function-pointer type, as the type of a member of a [**Type**](Type) (UDT), or as a parameter type in a [**Declare**](Declare) statement or an [**Interface**](Interface) member.

A delegate value is normally produced by **AddressOf**, which yields a delegate-typed reference to a regular procedure with a matching signature. For backwards compatibility, a delegate variable can also be assigned a plain **LongPtr** address obtained by other means — the value passes through unchecked. A delegate variable is called like a function: `result = myDelegate(arg1, arg2)`.

### Example

A basic delegate, declared, assigned, and called:

```tb
Private Delegate Function Operation (ByVal A As Long, ByVal B As Long) As Long

Public Function Addition(ByVal A As Long, ByVal B As Long) As Long
Return A + B
End Function

Private Sub Command1_Click()
Dim op As Operation = AddressOf Addition
MsgBox "Answer: " & op(5, 6)
End Sub
```

A delegate used as a UDT member, modelling the `lpfnHook` field of the Windows `CHOOSECOLOR` struct. Existing code that assigns a **Long**/**LongPtr** to `lpfnHook` continues to work; new code can assign **AddressOf** *Handler* directly and have the signature checked at compile time:

```tb
Public Delegate Function CCHookProc (ByVal hwnd As LongPtr, ByVal uMsg As Long, _
ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr

Public Type CHOOSECOLOR
lStructSize As Long
hwndOwner As LongPtr
hInstance As LongPtr
rgbResult As Long
lpCustColors As LongPtr
Flags As ChooseColorFlags
lCustData As LongPtr
lpfnHook As CCHookProc ' Typed function pointer instead of LongPtr.
lpTemplateName As LongPtr
End Type

Dim tCC As CHOOSECOLOR
tCC.lpfnHook = AddressOf ChooseColorHookProc
```

A **CDecl** delegate, used as the comparator parameter of the C-runtime `qsort` API:

```tb
Private Delegate Function LongComparator CDecl ( _
ByRef a As Long, _
ByRef b As Long _
) As Long

Private Declare PtrSafe Sub qsort CDecl Lib "msvcrt" ( _
ByRef pFirst As Any, _
ByVal lNumber As Long, _
ByVal lSize As Long, _
ByVal pfnComparator As LongComparator _
)
```

### See Also

- [**Declare** statement](Declare)
- [**Type** statement](Type)
- [**Interface** statement](Interface)
- [**Alias** statement](Alias)
- [Delegate Types](../../Features/Language/Delegates)
- [API Declarations](../../Features/Advanced/API-Declarations)
- [Enhanced Pointer Functionality](../../Features/Language/Pointers)
Loading