Skip to content

Commit 6ea7699

Browse files
authored
Merge pull request #62 from KubaO/staging, #56 from woeoio/vi
Split the monolithic features documentation into manageable sections.
2 parents b58bacd + ef60377 commit 6ea7699

File tree

79 files changed

+2260
-1522
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2260
-1522
lines changed

docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ _site
33
.jekyll-cache
44
.jekyll-metadata
55
*.af~lock~
6+
_bak

docs/Features/64bit.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: 64bit Compilation
3+
parent: Features
4+
nav_order: 9
5+
permalink: /Features/64bit
6+
---
7+
8+
# 64bit Compilation
9+
10+
twinBASIC can compile native 64bit executables in addition to 32bit. The syntax is compatible with VBA7 for this: the `LongPtr` data type and the standard to mark APIs `PtrSafe`.
11+
12+
## Example Syntax
13+
14+
```vb
15+
Public Declare PtrSafe Sub foo Lib "bar" (ByVal hWnd As LongPtr)
16+
```
17+
18+
## Important Considerations
19+
20+
> [!IMPORTANT]
21+
> There is a lot more required to get most 32bit apps to work properly as 64bit. Only some `Long` variables are to be changed, and this is determined by their C/C++ data types, of which there are many. Examples that need to be `LongPtr` include handles like `HWND, HBITMAP, HICON,` and `HANDLE`; pointers like `void*, PVOID, ULONG_PTR, DWORD_PTR,` and `LPWSTR/PWSTR/LPCWSTR/WCHAR*` when passed as `Long`; and the `SIZE_T` type found in CopyMemory and memory allocation functions.
22+
23+
While the `PtrSafe` keyword is not mandatory, these changes still must be made. Additionally, any code working with memory pointers must account for the fact all the types mentioned (and the many more not), as well as v-table entries, are now either 4 or 8 bytes, when most programmers have traditionally hard coded 4 bytes. There are also UDT alignment issues more frequently. This is all very complex and you should seek resources and advice when moving to 64bit (though remember, 32bit is still supported so this isn't a requirement).
24+
25+
For common Windows APIs and COM interfaces, a community-developed package is available that provides 64bit compatible definitions: [Windows Development Library for twinBASIC (WinDevLib)](https://github.com/fafalone/WinDevLib).
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
title: Enhanced API Declarations
3+
parent: Advanced Features
4+
nav_order: 4
5+
permalink: /Features/Advanced/API-Declarations
6+
---
7+
8+
# Enhancements to API and Method Declarations
9+
10+
twinBASIC provides several enhancements to API and method declarations to make working with external libraries easier.
11+
12+
## DeclareWide
13+
14+
The `DeclareWide` keyword, in place of `Declare`, disables ANSI<->Unicode conversion for API calls. This applies both directly to arguments, and to String arguments inside a UDT. For example, the following are equivalent in functionality:
15+
16+
```vb
17+
Public Declare PtrSafe Sub FooW Lib "some.dll" (ByVal bar As LongPtr)
18+
Public DeclareWide PtrSafe Sub Foo Lib "some.dll" Alias "FooW" (ByVal bar As String)
19+
```
20+
21+
Both represent a fully Unicode operation, but the allows direct use of the `String` datatype without requiring the use of `StrPtr` to prevent conversion.
22+
23+
> [!WARNING]
24+
> This does **not** change the underlying data types-- the `String` type is a `BSTR`, not an `LPWSTR`, so in the event an API returns a pre-allocated `LPWSTR`, rather than filling a buffer you have created, it will not provide a valid `String` type. This would be the case where an API parameter is given as `[out] LPWSTR *arg`.
25+
26+
## CDecl Support
27+
28+
The cdecl calling convention is supported both for API declares and methods in your code. This includes DLL exports in standard DLLs.
29+
30+
### Examples
31+
32+
```vb
33+
Private DeclareWide PtrSafe Function _wtoi64 CDecl Lib "msvcrt" (ByVal psz As String) As LongLong`
34+
```
35+
36+
```
37+
[ DllExport ]
38+
Public Function MyExportedFunction CDecl(foo As Long, Bar As Long) As Long
39+
```
40+
41+
### CDecl Callbacks
42+
43+
Support for callbacks using `CDecl` is also available. You would pass a delegate that includes `CDecl` as the definition in the prototype. Here is an example code that performs a quicksort using the [`qsort` function](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfw):
44+
45+
```vb
46+
Private Delegate Function LongComparator CDecl ( _
47+
ByRef a As Long, _
48+
ByRef b As Long _
49+
) As Long
50+
51+
Private Declare PtrSafe Sub qsort CDecl _
52+
Lib "msvcrt" ( _
53+
ByRef pFirst As Any, _
54+
ByVal lNumber As Long, _
55+
ByVal lSize As Long, _
56+
ByVal pfnComparator As LongComparator _
57+
)
58+
59+
Public Sub CallMe()
60+
Dim z() As Long
61+
Dim i As Long
62+
Dim s As String
63+
64+
ReDim z(10) As Long
65+
For i = 0 To UBound(z)
66+
z(i) = Int(Rnd * 1000)
67+
Next i
68+
qsort z(0), UBound(z) + 1, LenB(z(0)), AddressOf Comparator
69+
For i = 0 To UBound(z)
70+
s = s & CStr(z(i)) & vbNewLine
71+
Next i
72+
MsgBox s
73+
End Sub
74+
75+
Private Function Comparator CDecl( _
76+
ByRef a As Long, _
77+
ByRef b As Long _
78+
) As Long
79+
Comparator = a - b
80+
End Function
81+
```
82+
83+
## Support for Passing User-Defined Types ByVal
84+
85+
Simple UDTs can now be passed ByVal in APIs, interfaces, and any other method. In VBx this previously required workarounds like passing each argument separately.
86+
87+
```vb
88+
Public Declare PtrSafe Function LBItemFromPt Lib "comctl32" (ByVal hLB As LongPtr, ByVal PXY As POINT, ByVal bAutoScroll As BOOL) As Long
89+
90+
Interface IDropTarget Extends stdole.IUnknown
91+
Sub DragEnter(ByVal pDataObject As IDataObject, ByVal grfKeyState As KeyStateMouse, ByVal pt As POINT, pdwEffect As DROPEFFECTS)
92+
```
93+
94+
and so on. For this feature, a "simple" UDT is one that does not have members that are reference counted or are otherwise managed in the background, so may not contain interface, String, or Variant types. They may contain other UDTs.
95+
96+
## Variadic Arguments Support
97+
98+
With `cdecl` calling convention fully supported, twinBASIC can also handle variadic functions. In C/C++, those functions contain an ellipsis `...` as part of their arguments. This is represented in tB As `{ByRef | ByVal} ParamArray ... As Any()`. Note that `ByRef` or `ByVal` must be explicitly marked; implicit `ByRef` is not allowed.
99+
100+
### Example Using wsprintfW
101+
102+
Using the [given C/C++ prototype](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfw):
103+
104+
```cpp
105+
int WINAPIV wsprintfW(
106+
[out] LPWSTR unnamedParam1,
107+
[in] LPCWSTR unnamedParam2,
108+
...
109+
);
110+
```
111+
112+
The twinBASIC declaration and function using it can be written as shown:
113+
114+
```vb
115+
Private DeclareWide PtrSafe Function wsprintfW CDecl _
116+
Lib "user32" ( _
117+
ByVal buf As String, _
118+
ByVal format As String, _
119+
ByVal ParamArray args As Any() _
120+
) As Long
121+
122+
Private Sub Test()
123+
Dim buf As String = Space(1024)
124+
wsprintfW(buf, "%d %d %d", 1, 2, 3)
125+
MsgBox buf
126+
End Sub
127+
```
128+
129+
### va_list Arguments
130+
131+
For functions which contain the `va_list` type as part of their arguments the ParamArray declaration must be `ByRef`.
132+
133+
## PreserveSig
134+
135+
The `[PreserveSig]` attribute was described earlier for COM methods, but it can also be used on API declares. For APIs, the default is `True`. So therefore, you can specify `False` in order to rewrite the last parameter as a return.
136+
137+
### Example
138+
139+
```vb
140+
Public Declare PtrSafe Function SHGetDesktopFolder Lib "shell32" (ppshf As IShellFolder) As Long
141+
```
142+
143+
can be rewritten as:
144+
145+
```vb
146+
[PreserveSig(False)]
147+
Public Declare PtrSafe Function SHGetDesktopFolder Lib "shell32" () As IShellFolder`
148+
```

docs/Features/Advanced/Assembly.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
title: Direct Assembly Insertion
3+
parent: Advanced Features
4+
nav_order: 2
5+
permalink: /Features/Advanced/Assembly
6+
---
7+
8+
# Emit() and Naked Functions
9+
10+
Raw bytecode can be inserted into a binary with tB's `Emit()` function. To support this, functions can be marked as `Naked` to remove hidden tB code.
11+
12+
## Example
13+
14+
For example, the following is an implementation of the InterlockedIncrement compiler intrinsic that replaces the API in Microsoft C/C++ (adds one to `Addend` and returns the result, as an atomic operation which isn't guaranteed with regular code):
15+
16+
```vb
17+
Public Function InlineInterlockedIncrement CDecl Naked(Addend As Long) As Long
18+
#If Win64 Then
19+
Emit(&Hb8, &H01, &H00, &H00, &H00) ' mov eax,0x1
20+
Emit(&Hf0, &H0f, &Hc1, &H41, &H00) ' lock xadd DWORD PTR [rcx+0x4],eax
21+
Emit(&Hff, &Hc0) ' inc eax
22+
Emit(&Hc3) ' ret
23+
#Else
24+
Emit(&H8b, &H4c, &H24, &H04) ' mov ecx, DWORD PTR _Addend$[esp-4]
25+
Emit(&Hb8, &H01, &H00, &H00, &H00) ' mov eax, 1
26+
Emit(&Hf0, &H0f, &Hc1, &H01) ' lock xadd DWORD PTR [ecx], eax
27+
Emit(&H40) ' inc eax
28+
Emit(&Hc3) ' ret 0
29+
#End If
30+
End Function
31+
```
32+
33+
(Note: The `CDecl` calling convention is optional; you can write x86 assembly using `_stdcall` and simply omit the notation.)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: Class Features
3+
parent: Advanced Features
4+
nav_order: 5
5+
permalink: /Features/Advanced/Classes-and-Modules
6+
---
7+
8+
# Class and Module Enhancements
9+
10+
twinBASIC provides several enhancements for classes and modules.
11+
12+
## Parameterized Class Constructors
13+
14+
Classes now support a `New` sub with ability to add arguments, called as the class is constructed prior to the `Class_Initialize` event.
15+
16+
### Example
17+
18+
For example a class can have:
19+
20+
```
21+
[ComCreatable(False)]
22+
Class MyClass
23+
Private MyClassVar As Long
24+
Sub New(Value As Long)
25+
MyClassVar = Value
26+
End Sub
27+
End Class
28+
```
29+
30+
then created by `Dim mc As MyClass = New MyClass(123)` which sets `MyClassVar` on create. Note: Classes using this must be private, have the `[ComCreatable(False)]` attribute, or also contain `Class_Initialize()`. `Class_Initialize()` will replace `New` in callers of a compiled OCX. Within the project, only `New` will be used if present.
31+
32+
## Private/Public Modifiers for Modules and Classes
33+
34+
A private module or class won't have its members entered into the type library in an ActiveX project.
35+
36+
## ReadOnly Variables
37+
38+
In a class, module-level variables can be declared as `ReadOnly`, e.g. `Private ReadOnly mStartDate As Date`. This allows more complex constant assignments: you can use a function return to set it inline, `Private ReadOnly mStartDate As Date = Now()`, or `ReadOnly` constants can be set in `Class_Initialize` or `Sub New(...)` (see parameterized class constructors above), but everywhere else, they can only be read, not changed.
39+
40+
## Exported Functions and Variables
41+
42+
It's possible to export a function or variable from standard modules, including with CDecl.
43+
44+
### Examples
45+
46+
```
47+
[DllExport]
48+
Public Const MyExportedSymbol As Long = &H00000001
49+
50+
[DllExport]
51+
Public Function MyExportedFunction(ByVal arg As Long) As Long
52+
53+
[DllExport]
54+
Public Function MyCDeclExport CDecl(ByVal arg As Long)
55+
```
56+
57+
This is primarily used to create Standard DLLs (see [Project Types](../Project-Configuration/Project-Types.md)), but this functionality is also available in Standard EXE and other compiled project types.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: Multithreading
3+
parent: Advanced Features
4+
nav_order: 1
5+
permalink: /Features/Advanced/Multithreading
6+
---
7+
8+
# Thread Safety / Multithreading Support
9+
10+
While there's no native language syntax yet (planned), you can call `CreateThread` directly with no hacks. Previously, VBx and other BASIC languages typically required elaborate workarounds to be able to use `CreateThread` for anything but some specialized, extremely simple things. In twinBASIC, you can call it and all other threading APIs without any special steps, other than of course the careful management of doing threading at a low level like this.
11+
12+
## Example
13+
14+
In a new Standard EXE project, add a CommandButton and TextBox to your form:
15+
16+
```vb
17+
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
18+
19+
Private Declare PtrSafe Function CreateThread Lib "kernel32" ( _
20+
ByRef lpThreadAttributes As Any, _
21+
ByVal dwStackSize As Long, _
22+
ByVal lpStartAddress As LongPtr, _
23+
ByRef lpParameter As Any, _
24+
ByVal dwCreationFlags As Long, _
25+
ByRef lpThreadId As Long) As LongPtr
26+
27+
Private Declare PtrSafe Function WaitForSingleObject Lib "kernel32" ( _
28+
ByVal hHandle As LongPtr, _
29+
ByVal dwMilliseconds As Long) As Long
30+
31+
Private Const INFINITE = -1&
32+
33+
Private Sub Command1_Click() Handles Command1.Click
34+
Dim lTID As Long
35+
Dim lCurTID As Long
36+
Dim hThreadNew As LongPtr
37+
lCurTID = GetCurrentThreadId()
38+
hThreadNew = CreateThread(ByVal 0, 0, AddressOf TestThread, ByVal 0, 0, lTID)
39+
Text1.Text = "Thread " & lCurTID & " is waiting on thread " & lTID
40+
Dim hr As Long
41+
hr = WaitForSingleObject(hThreadNew, 30000&) 'Wait 30s as a default. You can use INFINITE instead if you never want to time out.
42+
Text1.Text = "Wait end code " & CStr(hr)
43+
End Sub
44+
45+
Public Sub TestThread()
46+
MsgBox "Hello thread"
47+
End Sub
48+
```
49+
50+
Under a single-threaded code, if you called `TestThread` before updating `Text1.Text`, the text wouldn't update until you clicked ok on the message box. But here, the message box in launched in a separate thread, so execution continues and updates the text, after which we manually choose to wait for the message box thread to exit.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
title: Static Linking
3+
parent: Advanced Features
4+
nav_order: 3
5+
permalink: /Features/Advanced/Static-Linking
6+
---
7+
8+
# Static Linking of OBJ and LIB Files
9+
10+
tB allows you to use properly compiled .lib and .obj files as statically linked libraries, using declares similar to DLLs, only referring a lib/obj file in your Miscellaneous files folder of your project. Once the file is in the project, it's set up with this syntax outside of declares.
11+
12+
## Example
13+
14+
Example from the sqlite sample:
15+
16+
```vb
17+
#If Win64 Then
18+
Import Library "/Miscellaneous/sqlite3_64.obj" As SQLITE3 Link "stdlib", "kernel32"
19+
#Else
20+
Import Library "/Miscellaneous/sqlite3_32.obj" As SQLITE3 Link "stdlib", "kernel32"
21+
#End If
22+
```
23+
24+
### Generic Syntax
25+
26+
```
27+
Import Libary "Relative resource path" As NAMESPACE Link "dependency1", "dependency2", '...
28+
```
29+
30+
## Using Imported Libraries
31+
32+
After that, you can use NAMESPACE in place of a DLL name, inside class/module declares:
33+
34+
```vb
35+
' Compiled sqlite-amalgamation-3440200 (v3.44.2)
36+
' using cmdline (MSVC): cl /c /Gw /Gy /GS- /DSQLITE_OMIT_SEH sqlite3.c
37+
#If Win64 Then
38+
Import Library "/Miscellaneous/sqlite3_64.obj" As SQLITE3 Link "stdlib", "kernel32"
39+
#Else
40+
Import Library "/Miscellaneous/sqlite3_32.obj" As SQLITE3 Link "stdlib", "kernel32"
41+
#End If
42+
43+
Module MainModule
44+
45+
Declare PtrSafe Function sqlite3_open CDecl Lib SQLITE3 (ByVal filename As String, ByRef ppDb As LongPtr) As Long
46+
Declare PtrSafe Function sqlite3_exec CDecl Lib SQLITE3 (ByVal pDb As LongPtr, ByVal sql As String, ByVal exec_callback As LongPtr, ByVal udp As LongPtr, ByRef errmsg As LongPtr) As Long
47+
'...
48+
```
49+
50+
> [!NOTE]
51+
> StdCall names will be mangled with argument sizes, e.g. `int myfunc(int x, short y);` would be `myfunc@6`. It therefore may be better to use `CDecl`.
52+
53+
A documentation page will be dedicated to more fully explaining this in the future; for now if you need help with it, visit the tB Discord or Discussions section of the GitHub repository and ask.

docs/Features/Advanced/index.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: Advanced Features
3+
parent: Features
4+
nav_order: 7
5+
permalink: /Features/Advanced/
6+
has_toc: false
7+
---
8+
9+
# Advanced Features
10+
11+
Advanced twinBASIC features for low-level programming and system integration.
12+
13+
## Topics
14+
15+
- [Multithreading](Multithreading) - Thread safety and multithreading support
16+
- [Assembly](Assembly) - Direct assembly insertion with Emit()
17+
- [Static Linking](Static-Linking) - Static linking of OBJ and LIB files
18+
- [API Declarations](API-Declarations) - Enhanced API and method declarations
19+
- [Class and Module Features](Classes-and-Modules) - Parameterized constructors, ReadOnly, and exports

0 commit comments

Comments
 (0)