twinBASIC Update: March 17, 2024

Highlights include independent TypeLibrary versioning and a detailed explanation of the new Runtime Tracing feature.

twinBASIC Update: March 17, 2024

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, 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, tweet me @NoLongerSet or email me at mike at nolongerset dot com.

Here are some links to get involved with the project:


Highlights

Independent TypeLibrary Versioning

BETA 469 added the following new TypeLibrary project settings:

  • Project: TypeLibrary Version (MAJOR)
  • Project: TypeLibrary Version (MINOR)
  • Project: TypeLibrary Version (AUTO INCREMENT)

It is important to note that these properties are not the same as the overall Project version properties, which may be set independently.

Why have two sets of version properties?  It comes down to binary compatibility.

TypeLibrary Version

  • A TypeLibrary is a binary description of interfaces, methods, and other data types provided by a COM component, such as an ActiveX control. The typelib version is crucial for clients that use these components to understand what interfaces and methods are available.
  • The TypeLibrary Version is important for compatibility and versioning of the COM interfaces. If you make changes to the public interfaces of your ActiveX control (such as adding new methods or properties), you should increment the typelib version to indicate that there has been a change in the API.
  • COM uses the typelib version to manage bindings to the interfaces at compile time and to ensure that the correct version of the component is loaded at runtime.
  • In the context of twinBASIC and VB6, the typelib version helps the development environment and other tools to distinguish between different versions of the same control when referenced by a project.

Project Version

  • The Project Version typically refers to the version of the overall software project/product. It is a more general versioning that indicates the release of the entire application or component, which may include changes that are not limited to the public interfaces.
  • This version is often used for display purposes, installer packages, and by the end-users to identify which version of the software they are using.
  • The Project Version does not necessarily have to change when the TypeLibrary Version changes unless the overall application changes warrant it.

Binary Compatibility

The TypeLibrary version is more crucial for binary compatibility purposes than changes to the Project version. Here’s why:

  • The TypeLibrary version directly affects binary compatibility because it describes the interfaces, methods, and other exposed types of a COM component like an ActiveX control.
  • When a client application binds to a COM component, it relies on the TypeLibrary to ensure that the component's interfaces match what the application expects. If the interfaces have changed (for example, if methods were added or removed), the TypeLibrary version should be incremented to indicate these changes to client applications.
  • Binary compatibility is maintained when client applications can use newer versions of the COM component without recompiling or changing their code, as long as the interfaces they rely on have not changed.
  • The Project version, on the other hand, is a broader indicator of the software's development stage. It might reflect changes in the software that don’t affect its exposed interfaces, such as internal bug fixes, performance improvements, or changes in implementation that are transparent to the client applications.
  • Incrementing the Project version does not necessarily mean there are changes to the binary interfaces of the software that would affect compatibility.

Maintaining binary compatibility is of particular concern when developing and distributing COM components, as it ensures that existing client applications do not break when the component is updated. Therefore, managing the TypeLibrary version carefully is essential for developers who want to ensure that their updates are backward compatible and do not disrupt the functionality of the applications that rely on their components.

By using separate version numbers for the Type Library and the Project, developers can use the Project Version to track changes to implementation (including bug fixes and performance improvements) while preserving the Type Library version for changes to the public interface (including adding and removing object methods) which affect binary compatibility.

Discord Chat Summary

* Auto-generated via Claude-2-100k on poe.com

Here is a summary of the key points from the General channel transcript:

Overview

Discussions this week focused on finishing usercontrols, resolving bugs with ActiveX controls, adding missing VBA features like LoadFromText, and exploring asynchronous message boxes and multithreading. Comparisons were made to replacing old VB6 systems and using C# async/await. Overall good progress on stability and missing VBA compatibility.

Key Points

  • Usercontrols work is starting, prioritizing commissioned control first then addressing issues list.
  • A "catastrophic failure" runtime bug was fixed when using ActiveX controls in some hosts. Tracing was crucial to catching this obscure bug.
  • LoadFromText and other Access-specific features require referencing Access libraries.
  • Async message boxes explored by launching MsgBox on separate thread.
  • Multithreading capabilities allow powerful options like async message boxes.
  • Immigration system debacle highlights VB6 replacement challenges.
  • C# async/await keywords are inspiration for making multithreading easier.

Conclusion

This week saw big strides in finishing usercontrol generation, fixing critical ActiveX bugs, and gaining more VBA compatibility like LoadFromText.

Replacement challenges faced by legacy VB6 systems were discussed, including some legacy VB tricks that may no longer work. Experimenting with async message boxes via multithreading highlights twinBASIC's capabilities that go beyond VB6. Multithreading and async patterns remain areas for future work.

Overall solid progress towards stability and VBA feature parity this week.

Around the Web

Runtime Tracing Explained

I missed this last week as it appeared in a brand new Discord channel named #tracing.

In this channel, Wayne highlighted and explained the new runtime tracing feature:

[Wayne]: In essence, this feature allows us to trace the running execution of tB generated code, without you having to add any explicit logging to your code - the log files are generated automatically after you enable the tracing features and build your projects.   Generated EXEs/OCXs/DLLs are still self-contained, but with the tracing features enabled the compiler emits extra code that automatically tracks various points of execution.

Here are Wayne's brief explanations for each trace flag:

  1. Trace procedures.  With this option ON, the log will include an entry for each procedure entry and exit.  The procedure type (property/sub/function) is shown, along with the procedure names.
  2. Trace Procedure Arguments.  With this option ON (in addition to option 1) the log output will also include decoding of the procedure arguments and most return values in the procedure entry log.  Only simple datatypes are currently logged (Byte, Integer, Long, String, Variant, etc).  Arrays/UDTs are not yet decoded here.  Return values from standard module functions are not currently logged, except for Variants/Decimals.
  3. Trace IDispatch::QueryInterface.   With this option ON, calls that reach the tB implementation of IDispatch:QueryInterface for any class will be logged.  This is handy when implementing something for external consumption, where you might be investigating what the external caller is expecting your class to implement.   As an example, for OCX controls we can monitor what interfaces the hosts applications are asking our objects for at runtime.
  4. Trace IDispatch::GetIDsOfNames.  Similar to 3 - this is for tracking when callers ask our objects for a late-bound method, which may or may not be implemented.
  5. Trace IDispatch::Invoke. Similar to 3 - this is for tracking when callers ask to invoke a late-bound method, which may or may not be implemented.
  6. Trace Window (HWND) messages.  With this option ON, every HWND message that passes through our window classes (form, controls, etc) will be logged.   In most cases, the constant name of the message is included, e.g. WM_PAINT, and of course the wParam/lParam values are also logged, as well as the LRESULT return values.
  7. Trace Debug.TracePrint.  With this option ON, explicit calls to Debug.TracePrint in your code will also reach the generated trace log. (edited)

"Note that some of these options will add a significant amount of log entries, and all of them affect performance, so choose wisely what you want to monitor.   If you're tracing to track down a crash, you're best putting all the options ON."

"Each thread gets its own SESSIONID, which is a GUID. As the compiler can run code on multiple threads, it is strongly recommended to include the ${SESSIONID} placeholder in the path, otherwise only the first thread will be able to create the log file, since it opens the file for exclusive write access.  For example, when evaluating constant expressions, the compiler can execute code in the compilation threads, and this can/will create its own trace log.  (This may be tweaked in future so that the compilation threads don't generate these trace logs)"

For more information about the IDispatch Interface, check out my article on the subject here:

The IDispatch Interface
For a COM object to support late binding in VBA, it must implement the IDispatch interface. Let’s explore IDispatch and its four methods.

For additional information and context, I've written more than a dozen other articles discussing various COM concepts.  You can access all those articles here:

COM - No Longer Set
The Component Object Model (COM) is the language-independent binary technology that underpins the entire Windows ecosystem. These articles explore the world of COM in varying levels of depth.

Changelog

Here are the updates from the past week.  You can also find this information by visiting the GitHub twinBASIC Releases page.

Releases · WaynePhillipsEA/twinbasic
Contribute to WaynePhillipsEA/twinbasic development by creating an account on GitHub.

ChatGPT Changelog Summary

* Auto-generated via ChatGPT, sorted in order of ChatGPT's opinion of "most impactful changes."

  • added: New project settings for controlling TypeLibrary Version, including 'MAJOR', 'MINOR', and 'AUTO INCREMENT' options to help manage ActiveX control versioning.
  • improved: The ActiveX Control sample now automatically increments the typelib version with each release, aiding in proper cache refreshing in hosts.
  • fixed: Resolved multiple issues, including the 'Debug.TracePrint' statement not functioning in compiled executables, SetFocus API problems in UserControls, and 'Catastrophic failure' errors when using ActiveX controls in certain hosts.
  • tip: To ensure that hosts correctly update cached typelib information, ActiveX controls should increase the typelib version number in each new release.

WARNING: The following issues are present in BETA builds 424 - 472 (the latest build as of publication):

BETA 469

  • fixed: Debug.TracePrint statement not working in compiled executables (producing empty line in trace output)
  • fixed: SetFocus API issue in UserControls [ commissioned work ]
  • added: project setting 'Project: TypeLibrary Version (MAJOR)' [ commissioned work ]
  • added: project setting 'Project: TypeLibrary Version (MINOR)' [ commissioned work ]
  • added: project setting 'Project: TypeLibrary Version (AUTO INCREMENT)' [ commissioned work ]
  • TIP: ActiveX controls designed for consumption by hosts that cache typelib information (e.g. UserForm .EXDs), should bump the typelib version number per release to ensure the cached typelib gets refreshed
  • improved: ActiveX Control sample now has the 'Project: TypeLibrary Version (AUTO INCREMENT)' option set [ commissioned work ]
  • fixed: 'Catastrophic failure' (and similar) runtime message in some instances when ActiveX generated control is used in some hosts [ commissioned work ]
  • fixed: UserControl PropertyChanged notifications are now ignored if they occur during certain events such as ReadProperties [ commissioned work ]

BETA 470

  • fixed: Debug.TracePrint statement causing compiler crash if included in a package
  • fixed: type library version number created in the registry did not use the correct hexadecimal format

BETA 471

  • fixed: 'Unexpected error' occurs when trying to compile a VB6 application that utilizes a tB-generated ActiveX control [ vbuser, discord ]

BETA 472

  • fixed: form designer location/size bubbles could move down inappropriately when designer area was small [ https://github.com//issues/1803 ]
  • fixed: some ComboBox edge cases on x64 builds [ discord, sokinkeso ]

Acknowledgements
  • Portions of this article's body generated with the help of ChatGPT

All original code samples by Mike Wolfe are licensed under CC BY 4.0