twinBASIC Update: June 10, 2025
Highlights include a new [ComExport] attribute, a new "TWINBASIC_BUILD_TYPE" compiler constant, and the continued expansion of the WinDevLib project.

On April 23, 2021, I helped Wayne Phillips introduce the world to twinBASIC at the Access DevCon Vienna conference. I boldly predicted that twinBASIC (along with the Monaco editor) would replace VBA and its outdated development environment by 2025. With that goal in mind, this weekly update is my attempt to keep the project fresh in the minds of the VBA development community.
Every Sunday Monday week, I will be providing updates on the status of the project, linking to new articles discussing twinBASIC, and generally trying to increase engagement with the project. If you come across items that should be included here, please leave a comment below.
Here are some links to get involved with the project:
- Custom twinBASIC IDE Installation Guide
- twinBASIC Discord Server (chat about the project)
- twinBASIC Wiki (list of new features not in VBx)
- GitHub Issue Tracker (report bugs)
- twinBASIC/VBx LinkedIn Group
Highlights
[ComExport] Attribute Added
You can now transform standard API declarations into fully reusable COM components with a single line of code.
The new [ComExport]
attribute allows you to publish API Declare
statements and Const
fields from a standard module directly into your ActiveX project's type library. Simply place the attribute before a Public Declare
or Public Const
line in any standard module within your ActiveX DLL or Control project. When compiled, these declarations become visible to any COM-aware client, such as VBA or VB6, allowing them to use your functions and constants just by adding a reference to your DLL. This eliminates the need for redundant Declare
statements in consumer projects, centralizing your API logic into a single, maintainable library.
This feature enables the creation of powerful, self-documenting API utility libraries that seamlessly integrate with the entire COM ecosystem.
Full Technical Recap
The [ComExport]
attribute was introduced in BETA 790 as a direct response to community requests. Its purpose is to allow developers to create ActiveX DLLs that export Windows API functions and their associated constants, making them directly accessible to COM clients without requiring the client to have its own corresponding Declare
statements.
How To Use It: A Practical Example
-
Create a twinBASIC ActiveX DLL Project. Let's call it
ApiHelpers
. -
Add Sample Code to a Standard Module. Your
MainModule.twin
file should look like this:Module MainModule ' This project type is set to 'ActiveX DLL' in the Settings file [ComExport] Public Const WM_SETTEXT = &HC [ComExport] Public Declare PtrSafe Function FindWindowW Lib "user32" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr [ComExport] Public Declare PtrSafe Function SendMessageW Lib "user32" _ (ByVal hWnd As LongPtr, ByVal Msg As Long, _ ByVal wParam As LongPtr, ByVal lParam As String) As LongPtr End Module
-
Build the Project. File > Build. This will create and register
ApiHelpers.dll
. -
Use it in a COM Client (e.g., Excel VBA):
- Open the VBA editor, go to Tools -> References, and add a reference to "ApiHelpers".
- You can now write the following code without any local
Declare
statements:Sub SetNotepadTitle() Dim hWnd As LongPtr hWnd = ApiHelpers.FindWindowW("Notepad", vbNullString) If hWnd <> 0 Then ApiHelpers.SendMessageW hWnd, ApiHelpers.WM_SETTEXT, 0, "Hello from VBA!" End If End Sub
-
Run the test code: Ensure Notepad is already running, then run the
SetNotepadTitle()
procedure above. The Notepad window's title will be changed to "Hello from VBA!"




Important Technical Considerations
-
Project Scope: The
[ComExport]
attribute is only effective in projects compiled as an ActiveX component (e.g., ActiveX DLL, ActiveX Control) and only applies toPublic
declarations within a standard module. -
DLL Path Resolution: The
Lib
string in yourDeclare
statement is critical. For a client like VBA to find the target DLL (e.g.,user32.dll
), it must be in a standard system search path. If you are exporting an internal function from your own DLL, be aware that the client's current working directory may not be where your DLL is located. The most reliable method is to ensure any custom DLLs are placed in a location on the systemPATH
. -
Aliases and Ordinals: The feature correctly handles aliases. The name used in the
Declare
statement will be the name exposed in the type library, while theAlias
(whether a string or an ordinal number) will be used as the actual function entry point. -
Automatic UDT Export: If an exported
Declare
statement uses a User-Defined Type (UDT) as a parameter, twinBASIC will automatically export the UDT's definition to the type library as well. -
Sub
vs.Function
Declarations: An initial bug causedDeclare Sub
statements to be exported incorrectly. This was fixed in BETA 801. Ensure you are using this version or newer to avoid issues with functions that have avoid
return type.
*This section was generated via Gemini-2.5-Pro based on this twinBASIC Discord channel discussion.
Fine-Tune Builds with a New Compiler Constant
You can now write a single codebase that automatically tailors itself for different compilation targets, such as a Standard EXE or an ActiveX Control.
Introduced in BETA 799, the new TWINBASIC_BUILD_TYPE
compiler constant directly addresses a key challenge in creating components for both modern and legacy environments. As detailed in a GitHub issue by user fafalone
, an ActiveX control using the modern LongLong
data type would cause automation errors in VB6, which does not support it in type libraries. The previous workaround of using #If Win64
to switch to the compatible Currency
type was too broad, as it unnecessarily penalized 32-bit twinBASIC builds that can handle LongLong
perfectly. With this new constant, developers can now use #If TWINBASIC_BUILD_TYPE = "ActiveX Control"
to isolate compatibility code, ensuring that only the builds intended for legacy hosts receive the necessary changes.
The following values are supported:
#If TWINBASIC_BUILD_TYPE = "Standard EXE" Then ...
#If TWINBASIC_BUILD_TYPE = "Standard DLL" Then ...
#If TWINBASIC_BUILD_TYPE = "ActiveX DLL" Then ...
#If TWINBASIC_BUILD_TYPE = "ActiveX Control" Then ...
This constant gives developers precise, granular control to maximize compatibility for legacy targets without compromising modern features for other project types.
*The initial draft for this section was generated via Gemini-2.5-Pro.
Discord Chat Summary
* Auto-generated via Claude-Sonnet-4
Overview
This week's discussions in the twinBASIC general channel focused heavily on language compatibility features, WinDevLib improvements, and practical development challenges. The community engaged in detailed technical conversations about string conversion functions, Unicode support, and COM interface handling, while several bug reports led to immediate fixes and updates.
Language Compatibility & Unicode Support
- waynephillipsea confirmed that
CStr()
conversion from Integer arrays (WCHAR) to String is not currently supported but has been mentioned for future consideration - The community explored Chinese character handling, with bclothier and fafalone explaining the proper use of
ChrW()
instead ofChr()
for Unicode characters - fafalone demonstrated twinBASIC's advanced Unicode support, showing that identifiers can use emoji characters in types, constants, and function names
- Discussion highlighted encoding challenges when migrating existing non-English VBx code that uses
Chr()
with MBCS encoding
WinDevLib Updates & Bug Fixes
- Multiple WinDevLib issues were identified and resolved, including duplicate
WSASocket
declarations and missingclosesocket
function - fafalone fixed the
COINIT_MULTITHREADED
constant value and added missingIFilter
return values from Filterr.h - waynephillipsea suggested exploring AI assistance for checking WinDevLib definitions, with fafalone reporting mixed but promising initial results with Claude
- Interface method overloading and
[PreserveSig]
attribute usage was explained in detail for handling HRESULT returns
Development Tools & IDE Features
- Discussion of shell context menu implementation revealed that the 30-year-old Brad Martinez approach is still necessary, though modern helpers simplify the process
- waynephillipsea acknowledged that an Object Browser feature is planned but currently limited by development time constraints
- A live save issue was reported and resolved through compiler restart, highlighting the new save failure detection system's effectiveness
Bug Reports & Fixes
- Delegate functionality in classes was identified as broken in the latest beta, with a bug report filed
- waynephillipsea addressed a driver compilation issue between versions 785 and 795 related to HRESULT checking changes
- The new save failure detection system successfully prevented data loss during a file handling issue
Conclusion
The week demonstrated strong community collaboration in identifying and resolving compatibility issues, particularly around Unicode handling and WinDevLib functionality. The immediate response to bug reports and the detailed technical explanations provided by core contributors show the project's commitment to maintaining VB6 compatibility while adding modern features. The discussion of AI-assisted code checking suggests potential future improvements to development workflows and library maintenance.
Around the Web
WinDevLib Continues to Grow
If you're not familiar with fafalone's Windows Development Library "twinPACK", you should be. To get up to speed, check out this article I wrote on the topic last April:

Along those lines, fafalone posted the following in the Discord show-and-tell channel (emphasis in original):
Just as a status update, WDL continues to expand all the time, so it's worth getting new versions. As of v8.12.552, WinDevLib now has: Over 10,000 APIs (~13100 - A/W variants) ~3100 COM interfaces 7200Type
s, 6500Enum
s, and about 20,000Public Const
s Anything missing from the common features let me know, any additional special sets you'd like covered, let me know. (A few are still on the todo list pending tB nativeAlias
support; OpenGL and SQL, mainly)
Changelog
Here are the updates from the past week. You can also find this information by visiting the GitHub twinBASIC Releases page.
AI-Generated Changelog Summary
* Auto-generated via Claude-Sonnet-4, sorted in order of its opinion of "most impactful changes."
• New Build Type Compiler Constant: Added TWINBASIC_BUILD_TYPE
constant for conditional compilation based on project type ("Standard EXE", "Standard DLL", "ActiveX DLL", "ActiveX Control")
• Improved ActiveX Control Support: Enhanced placement and behavior of twinBASIC ActiveX controls on Access forms, including proper sizing and focus handling for multiple controls
• Enhanced Type Library Features: Added [ComExport]
attribute support for API declares and constants in standard modules, allowing better COM interoperability and type library exposure
• Runtime Codepage Configuration: New project setting ("Project: Runtime Windows Codepage") for customizing runtime ANSI codepage used by functions like Chr()
, String()
, and StrConv()
• IDE and Designer Improvements: Fixed form designer issues with control arrays, copy/paste operations, and font object sharing; markdown files in packages now default to preview mode
• Enhanced Debugger Stability: Resolved crashes when stepping through Debug.Assert
failures and improved overall debugging reliability
WARNING: The following issues are present in BETA builds 623 - 802 (the latest build as of publication):
- IMPORTANT: This is an interim/experimental release. It includes significant changes, so some instability is to be expected. [Editor's Note: Rolling back to BETA 622 may be necessary if any of the KNOWN ISSUES below affect your project.]
- KNOWN ISSUE: Controls are not being destroyed properly by the form designer, causing big memory leaks (broken in this build)
- there are known memory leaks in these versions, so memory usage will be higher than at the Version 1.0 release
BETA 788
- fixed: (regression since BETA 786) compiler performance degradation over time when large projects are edited
- fixed: placing a tB AX control onto an Access form would not honour the original size until resized manually [ commissioned work, Tecman ]
- fixed: AX UIDeactivate implementation to prevent focus issues with having multiple tB AX controls on Access forms [ commissioned work, Tecman ]
- fixed: 'Override entry point' project option was broken in recent builds [ fafalone, discord ]
BETA 789
- fixed: form designer issue of newly placed controls sharing Font object inappropriately until designer is reloaded [ fafalone, discord ]
BETA 790
- added: support [ComExport] attribute on API declares in standard modules, for exposure in generated type libraries [ VanGoghGaming, discord ]
- added: support [ComExport] attribute on constant fields in standard modules, for exposure in generated type libraries [ VanGoghGaming, discord ]
BETA 791
- fixed: some expressions without a return value (using Sub/void functions) were allowed to be assigned to a variable, with errors only picked up during the final codegen stage [ XYplorer ]
- fixed: conversions from UDT to intrinsic basic types would not show an error until final codegen stage [ XYplorer ]
- fixed: temporarily disabled one of the recent performance improvements to help with stability [ XYplorer ]
BETA 792
- fixed: re-enabled one of the recent performance improvements, now fixed [ XYplorer ]
BETA 793
- improved: general compiler stability
BETA 794
- added: project setting 'Project: Runtime Windows Codepage' for changing the runtime ANSI codepage used by functions such as Chr(), String() and StrConv(), other cases to follow [ loquat, discord ]
BETA 795
- fixed: (regression in BETA 791) compiler crash in some instances
BETA 796
- fixed: runtime HRESULT internal error checks now disabled in kernel compilation mode to avoid dependencies [ fafalone, discord ]
BETA 797
- added: support for va_list ParamArray with __stdcall calling convention [ fafalone, discord ]
- fixed: IDE internal error, Cannot set properties of undefined (setting '0') [ fafalone, discord ]
- fixed: (regression) Menu ShortcutId could not be set in the form designer [ fafalone, discord ]
BETA 798
- fixed: AutoSize property now doesn't auto resize if the new picture is Nothing or empty [ XYplorer, discord ]
- improved: HScollBar and VScrollBar control implementations rewritten to better match VBx
- fixed: (regression since BETA 786) Delegates declared in form class modules were broken [ fafalone, discord ]
BETA 799
- added: themeable properties SymbolNamedOperatorColor, SymbolNamedOperatorFontStyle, SymbolNamedOperatorFontWeight, SymbolNamedOperatorTextDecoration [ https://github.com/twinbasic/twinbasic/issues/2139 ]
- improved: markdown files (*.md) in referenced packages now alwyas open in markdown-preview mode [ https://github.com/twinbasic/twinbasic/issues/2136 ]
- fixed: Err object optimization edge case [ https://github.com/twinbasic/twinbasic/issues/2134 ]
- added: compiler constant 'TWINBASIC_BUILD_TYPE', e.g. "Standard EXE", "Standard DLL", "ActiveX DLL", "ActiveX Control" based on root project setting [ https://github.com/twinbasic/twinbasic/issues/2122 ]
- fixed: pressing F8/F10 to step over a Debug.Assert failure would crash the compiler [ https://github.com/twinbasic/twinbasic/issues/2135 ]
- improved: general stability of the debugger [ https://github.com/twinbasic/twinbasic/issues/2135 ]
BETA 800
- fixed: (regression) form designer, 'duplicate (same name)' option was broken [ https://github.com/twinbasic/twinbasic/issues/2016 ]
- fixed: (regression) form designer, various issues with copy & paste [ sokinkeso, discord ]
BETA 801
- fixed: using [ComExport] on a Declare Sub would produce an invalid definition in the type library [ VanGoghGaming ]
- updated: 1 language pack (German)
- special thanks to our community members for the new/updated language packs (Krool)
BETA 802
- fixed: in some situations UserControl Resize event could fire before InitProperties/ReadProperties [ sokinkeso, discord ]