diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..f40fbd8b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-cache +.jekyll-metadata +vendor diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 00000000..3a16ab53 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,25 @@ +--- +permalink: /404.html +layout: page +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/docs/CustomControls/Defining a CustomControl.md b/docs/CustomControls/Defining a CustomControl.md new file mode 100644 index 00000000..6077fa95 --- /dev/null +++ b/docs/CustomControls/Defining a CustomControl.md @@ -0,0 +1,91 @@ +--- +title: Defining a CustomControl +parent: CustomControls +nav_order: 2 +permalink: /CustomControls/Defining/ +--- +# Defining a CustomControl +A CustomControl is simply an ordinary twinBASIC class, with a few extra attributes and requirements. + +{: .tip} +> It is highly advisable to look at and experiment with the sample project provided with twinBASIC before trying to implement your own CustomControl. + +![Custom Control Sample Project](Images/ccSampleProject.png) + +*** +## CustomControl() attribute +![CustomControl attribute](Images/ccCustomControlAttribute.png) + +This is a required attribute for all CustomControls. You must provide the relative path to an image file within your project that can be used to identify your control in the form designer toolbox. We recommend that you put the image file in the Miscellaneous folder in your project. + +![CustomControl GridImage Folder](Images/ccGridButtonImage.png) + +*** +## ClassId() attribute +![CustomControl ClassId Attribute](Images/ccClassIdAttribute.png) + +This is a required attribute for all CustomControls. You must provide a unique CLSID (GUID) in order for the form engine to work with your control. + +{: .tip } +> If you enter `[ ClassId () ]` twinBASIC helps you out - just press the 'insert a randomly generated GUID' text: + +![CustomControl ClassId auto-generate](Images/ccClassIdInsert.png) + +*** +## COMCreatable() attribute +![CustomControl COMCreatable attribute](Images/ccCOMCreatable.png) + +This is an optional attribute, but it is usually advisable to set this attribute to False, as you don't need to instantiate CustomControls from external COM environments. + +*** +## Must implement ICustomControl +![CustomControl ICustomControl interface](Images/ccICustomControl.png) + +All CustomControls *must* implement CustomControls.ICustomControl. This interface currently has 3 methods that you must implement: + +``` vb +Sub Initialize(ByVal Context As CustomControlContext) +``` + +This method is called when your control is attached to a form. You must store the provided Context object in a class field as it offers a `Repaint()` method for informing the form engine that something in your control has changed and needs to be repainted. + +``` vb +Sub Destroy() +``` + +This method is called when your control is detached from a form. This allows an opportunity to break circular references so that your object instance can be destructed properly. The implementation for this can often be left empty provided you don't create circular references in objects. + +``` vb +Sub Paint(ByVal Canvas As Canvas) +``` + +This is the most interesting part for a CustomControl. As such, it gets its own section, see [Painting / drawing to your control](../Painting/) + +*** +## Minimum set of properties +As twinBASIC doesn't yet support inheritance, you must expose a set of common properties (class fields) for all CustomControls: + +``` vb +Public Name As String +Public Left As CustomControls.PixelCount +Public Top As CustomControls.PixelCount +Public Width As CustomControls.PixelCount +Public Height As CustomControls.PixelCount +Public Anchors As Anchors = New Anchors +Public Dock As CustomControls.DockMode +Public Visible As Boolean +``` + +The form designer and the form engine work with these properties, so it is important to include them in your CustomControl class. + +Note that the form designer works with pixel values which are not DPI-scaled. So the Left/Top/Width/Height properties of your control do not reflect DPI scaling. For example, if your control has a width of 50 pixels, then at DPI 150%, then the actual drawing width is 75 pixels ( see [Painting / drawing to your control](CustomControls/Painting/)). + +*** +## Must have a serialization constructor +CustomControls *must* offer a serialization constructor: + +``` vb +Public Sub New(Serializer As SerializationInfo) +``` + +The passed in Serializer object offers a `Deserialize()` method that you call in order to load the properties that have been set for your control via the form designer. See [Property Sheet and Object Serialization](CustomControls/Properties/) for further information. \ No newline at end of file diff --git a/docs/_samples/customcontrols/ccCOMCreatable.png b/docs/CustomControls/Images/ccCOMCreatable.png similarity index 100% rename from docs/_samples/customcontrols/ccCOMCreatable.png rename to docs/CustomControls/Images/ccCOMCreatable.png diff --git a/docs/_samples/customcontrols/ccClassIdAttribute.png b/docs/CustomControls/Images/ccClassIdAttribute.png similarity index 100% rename from docs/_samples/customcontrols/ccClassIdAttribute.png rename to docs/CustomControls/Images/ccClassIdAttribute.png diff --git a/docs/_samples/customcontrols/ccClassIdInsert.png b/docs/CustomControls/Images/ccClassIdInsert.png similarity index 100% rename from docs/_samples/customcontrols/ccClassIdInsert.png rename to docs/CustomControls/Images/ccClassIdInsert.png diff --git a/docs/_samples/customcontrols/ccCustomControlAttribute.png b/docs/CustomControls/Images/ccCustomControlAttribute.png similarity index 100% rename from docs/_samples/customcontrols/ccCustomControlAttribute.png rename to docs/CustomControls/Images/ccCustomControlAttribute.png diff --git a/docs/CustomControls/Images/ccEvents.png b/docs/CustomControls/Images/ccEvents.png new file mode 100644 index 00000000..8722b9e0 Binary files /dev/null and b/docs/CustomControls/Images/ccEvents.png differ diff --git a/docs/_samples/customcontrols/ccGridButtonImage.png b/docs/CustomControls/Images/ccGridButtonImage.png similarity index 100% rename from docs/_samples/customcontrols/ccGridButtonImage.png rename to docs/CustomControls/Images/ccGridButtonImage.png diff --git a/docs/_samples/customcontrols/ccICustomControl.png b/docs/CustomControls/Images/ccICustomControl.png similarity index 100% rename from docs/_samples/customcontrols/ccICustomControl.png rename to docs/CustomControls/Images/ccICustomControl.png diff --git a/docs/CustomControls/Images/ccMyEnumFieldPropertySheet.png b/docs/CustomControls/Images/ccMyEnumFieldPropertySheet.png new file mode 100644 index 00000000..eae21a36 Binary files /dev/null and b/docs/CustomControls/Images/ccMyEnumFieldPropertySheet.png differ diff --git a/docs/CustomControls/Images/ccMyFieldArray.png b/docs/CustomControls/Images/ccMyFieldArray.png new file mode 100644 index 00000000..2fb60808 Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldArray.png differ diff --git a/docs/CustomControls/Images/ccMyFieldClass.png b/docs/CustomControls/Images/ccMyFieldClass.png new file mode 100644 index 00000000..759bb1fd Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldClass.png differ diff --git a/docs/CustomControls/Images/ccMyFieldCustomProperty.png b/docs/CustomControls/Images/ccMyFieldCustomProperty.png new file mode 100644 index 00000000..6ce8624c Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldCustomProperty.png differ diff --git a/docs/CustomControls/Images/ccMyFieldJson1a.png b/docs/CustomControls/Images/ccMyFieldJson1a.png new file mode 100644 index 00000000..4c7ead14 Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldJson1a.png differ diff --git a/docs/CustomControls/Images/ccMyFieldPropertySheet1a.png b/docs/CustomControls/Images/ccMyFieldPropertySheet1a.png new file mode 100644 index 00000000..e8cfdb12 Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldPropertySheet1a.png differ diff --git a/docs/CustomControls/Images/ccMyFieldPropertySheet1b.png b/docs/CustomControls/Images/ccMyFieldPropertySheet1b.png new file mode 100644 index 00000000..13bd7327 Binary files /dev/null and b/docs/CustomControls/Images/ccMyFieldPropertySheet1b.png differ diff --git a/docs/_samples/customcontrols/ccSampleProject.png b/docs/CustomControls/Images/ccSampleProject.png similarity index 100% rename from docs/_samples/customcontrols/ccSampleProject.png rename to docs/CustomControls/Images/ccSampleProject.png diff --git a/docs/CustomControls/Introduction.md b/docs/CustomControls/Introduction.md new file mode 100644 index 00000000..d7141923 --- /dev/null +++ b/docs/CustomControls/Introduction.md @@ -0,0 +1,20 @@ +--- +title: Introduction +parent: CustomControls +nav_order: 1 +permalink: /CustomControls/Introduction/ +--- + +### Introduction + +twinBASIC now offers experimental support for CustomControls. CustomControls are implemented using the BASIC language, allowing implementers to design controls directly from the twinBASIC environment. + +A few highlights; +- completely custom drawn controls, with no external or third-party dependencies (tiny footprint) +- support 32-bit RGBA for full alpha-transparency +- support high-DPI modes (per-monitor), requiring little thought whilst designing new controls +- full debugging support via the usual twinBASIC integrated debugger +- designed for efficiency so that supporting complex controls with hundreds of elements (e.g. a DataGrid with 100's of cells) is easily possible +- designed for flexibility, allowing for curved corners, multiple borders, background gradients and much more +- the form engine supports anchoring and docking without any considerations needed for CustomControl implementers +- simple property sheet synchronization via the built-in form designer \ No newline at end of file diff --git a/docs/CustomControls/Notes about the form designer.md b/docs/CustomControls/Notes about the form designer.md new file mode 100644 index 00000000..d4068a55 --- /dev/null +++ b/docs/CustomControls/Notes about the form designer.md @@ -0,0 +1,10 @@ +--- +title: Notes About the Form Designer +parent: CustomControls +nav_order: 5 +permalink: /CustomControls/Notes/ +--- + +# Notes About the Form Designer + +For the painting of controls in the form designer, CustomControl instances are instantiated and then release immediately after painting has finished. \ No newline at end of file diff --git a/docs/CustomControls/Painting-drawing to your control.md b/docs/CustomControls/Painting-drawing to your control.md new file mode 100644 index 00000000..2f4e7faa --- /dev/null +++ b/docs/CustomControls/Painting-drawing to your control.md @@ -0,0 +1,99 @@ +--- +title: Painting / Drawing to Your Control +parent: CustomControls +nav_order: 4 +permalink: /CustomControls/Painting/ +--- + +# Painting / Drawing to Your Control + +### The ICustomControl.Paint method +This is by far the most important method of a CustomControl. It tells the form engine exactly how you want it to render your control. + +{: .tip } +> It is highly advisable to look at and experiment with the sample project provided with twinBASIC before trying to implement your own CustomControl. + +``` vb +Private Sub OnPaint(ByVal Canvas As CustomControls.Canvas) _ + Implements ICustomControl.Paint +``` + +You are passed a Canvas object that offers the following methods: + +``` +Canvas.Width As Long [Property-Get] +Canvas.Height As Long [Property-Get] +Canvas.Dpi As Long [Property-Get] +Canvas.DpiScaleFactor As Double [Property-Get] +Canvas.AddElement(Descriptor As ElementDescriptor) +``` + +`Canvas.Width` and `Canvas.Height` are the absolute pixel sizes that your control is drawing to. Unlike your controls Width/Height properties that are not DPI-scaled, the `Canvas.Width` and `Canvas.Height` values **are** DPI-scaled. + +The `Canvas.Dpi` property represents the DPI setting in Windows. If no DPI scaling is in effect, this value is 96. For example, if you have scaling set at 150% on your monitor, then the `Canvas.Dpi` property will be 144. + +The `Canvas.DpiScaleFactor` property gives a floating point value representing the DPI scaling percentage. A value of 1 indicates no scaling. For example, if you have scaling set at 150% on your monitor, then the `Canvas.DpiScaleFactor` property will be 1.5. + +The `Canvas.AddElement` method is used for adding elements to your control. An *element* is considered to be something that the form-engine will render for you. For example, you might have a grid control that displays 100 cells at a time. Each of those cells would be an *element*. Elements can overlap each over (allowing for opacity/transparency). The form engine draws them in the order that you call AddElement, meaning that the last element added will have the highest z-order. + +*** +### AddElement(ElementDescriptor) +The AddElement method takes a single argument; an ElementDescriptor. ElementDescriptor is a UDT that defines exactly how the element will be drawn and how it reacts to events like mouse clicks. + +``` vb +Public Type ElementDescriptor + OnClick As LongPtr ' event function callback pointer + OnDblClick As LongPtr ' event function callback pointer + OnMouseDown As LongPtr ' event function callback pointer + OnMouseUp As LongPtr ' event function callback pointer + OnMouseEnter As LongPtr ' event function callback pointer + OnMouseLeave As LongPtr ' event function callback pointer + OnMouseMove As LongPtr ' event function callback pointer + OnScrollH As LongPtr ' event function callback pointer + OnScrollV As LongPtr ' event function callback pointer + Left As Long ' pixel offset (control relative, DPI scaled) + Top As Long ' pixel offset (control relative, DPI scaled) + Width As Long ' pixel width (DPI scaled) + Height As Long ' pixel width (DPI scaled) + Cursor As MousePointerConstants ' cursor/pointer icon + TrackingIdX As LongLong ' for tracking this element, passed to events + TrackingIdY As LongLong ' for tracking this element, passed to events + Text As String ' the text to render + TextRenderingOptions As TextRendering ' options to customize text rendering (object) + BackgroundFill As Fill ' options to customize back fill rendering (object) + Corners As Corners ' options to customize corner rendering (object) + Borders As Borders ' options to customize border rendering (object) +End Type +``` + +*** +### Tips +- Each time your OnPaint method is called, you start with a blank canvas. + +- Left/Top/Width/Height can legitimately be outside of the canvas area. For example, negative Left/Top, or a Width/Height past the Canvas.Width/Canvas.Height has no ill-effects. The form engine will clip everything appropriately for you, allowing for much simpler designing of your control. + +- You should put thought into making the Paint routine efficient. Try not to instantiate COM objects, and when drawing multiple similar elements, try to re-use ElementDescriptors by setting up common properties outside of loops (see WaynesGrid for examples of this) + +- TrackingIdX and TrackingIdY are important when you have multiple elements within a control. The two values, when combined, should uniquely represent the element, and must be maintained if your Paint routine is called again. This is needed for supporting events. For example, in a grid control, each cell would have a TrackingIdX / TrackingIdY value associated with it, given the X/Y co-ordinates of the cell. + +- Currently, only mouse events are provided, but focus events are coming soon, as well as keyboard events. + +- You can use class-based event handlers by simply using the `AddressOf MyEvent` which is now possible to use even on class members. You can see this used frequently in the samples, such as WaynesGrid. All mouse events have the following format: + +``` vb +Class MyCustomControl + '... + Private Sub MyClickEvent(ByRef EventInfo As MouseEvent) + MsgBox "You clicked me!" + End Sub + + Private Sub OnPaint(ByVal Canvas As CustomControls.Canvas) _ + Implements ICustomControl.Paint + Dim MyDescriptor As ElementDescriptor + MyDescriptor.OnClick = AddressOf MyClickEvent + End Sub +``` + +EventInfo (MouseEvent) provides mouse information such as the relative X/Y position of the mouse, plus the TrackingX/Y values discussed earlier. + +- When you call Canvas.AddElement, your element goes into a render pipeline. It is **not** immediately painted to the screen. The render pipeline is compared to the previous render pipeline that was provided by you in the last OnPaint call, and the tB form engine will only redraw areas of the control that have changed. This allows for efficient painting of controls whilst not needing to be concerned about the finer details of how to do partial repainting. \ No newline at end of file diff --git a/docs/CustomControls/Property sheet and object serialization.md b/docs/CustomControls/Property sheet and object serialization.md new file mode 100644 index 00000000..190f6b3f --- /dev/null +++ b/docs/CustomControls/Property sheet and object serialization.md @@ -0,0 +1,82 @@ +--- +title: Property Sheet and Object Serialization +parent: CustomControls +nav_order: 3 +permalink: /CustomControls/Properties/ +--- +# Property Sheet and Object Serialization +The form designer property sheet will pickup any **_public_** custom properties (fields) that you expose via your CustomControl class. For example, adding a field `Public MyField As Long` will then automatically show up in the control property sheet in the form designer: + +![CustomControl MyField propertySheet](Images/ccMyFieldPropertySheet1a.png) + +This is then persisted to your project as properties inside your form JSON structure: + +![CustomControl MyField JSON](Images/ccMyFieldJson1a.png) + +The key to making this work is your serialization constructor, which might look something like this: + +``` vb +Public Sub New(Serializer As SerializationInfo) + If Not Serializer.Deserialize(Me) Then + InitializeDefaultValues ' you implement this + End If +End Sub +``` + +If `Deserialize(Me)` returns `True`, then your class properties were synchronized with the properties set via the form designer. If it returns `False` then the control has just been added to the form, and this gives you an opportunity to setup any suitable default values for your custom public properties. The form designer notices default values you set within the serialization constructor, so that your property sheet is kept in-sync. + +*** +## Default Values +An alternative method for setting up default values is to inline them into the class field definition: + +![CustomControl MyField = 42](Images/ccMyFieldPropertySheet1b.png) + +The `Deserialize(Me)` call inside your serialization constructor will overwrite the property value if the control is being synchronized from the persisted property sheet data. + +*** +## Enumerations +Enumerations that you define in your twinBASIC project are supported. Simply expose a class field with the enumeration: + +![CustomControl enumeration property sheet example](Images/ccMyEnumFieldPropertySheet.png) + +Note: Enumerations are persisted to the form JSON structure as strings, so bare this in mind when making changes/updates to a CustomControl so that you don't introduce breaking changes by renaming an enumeration value. + +*** +## Objects +Class objects that you define in your twinBASIC project are supported. You ***must*** supply a ClassId attribute for any exposed object, so that the serialization can identify it. + +![CustomControl class property sheet example](Images/ccMyFieldClass.png) + +*** +## Arrays +Arrays are supported. The form designer allows for adding new elements, removing elements, and re-ordering of elements (via drag/drop). + +![CustomControl array property sheet example](Images/ccMyFieldArray.png) + +*** +## Property Get / Let +Custom property procedures are supported. You will find that using Property Get / Let procedures is required if you want property changes to trigger repainting of your control. + +![CustomControl custom property example](Images/ccMyFieldCustomProperty.png) + +Note that _**private**_ fields and properties do not form part of the serialization, and so will not appear on the property sheet. + +*** +## Avoid Variants +The serialization does not support Variants or generic Objects. Always use strongly-typed datatypes. + +*** +## Events +Events that you define in your class will be exposed in the Events property sheet: + +![CustomControl attribute](Images/ccEvents.png) + +At the moment, the form-designer doesn't yet support code-behind-forms, so this feature is not yet complete. + +*** +## Tips +- If you make changes to your CustomControl class, such as exposing new properties or changing how a control is drawn, these changes will get reflected immediately to any open form designers. Form designers will show a 'resync' button when you return to them, once pressed the changes will be apparent. + +- The serialization happens via JSON when running in the IDE, but via a binary format when running in a compiled DLL/EXE. The `SerializationInfo` object that is passed to your serialization constructor is a different implementation when running in the IDE, but this should be transparent to you as a CustomControl implementer. + +- When making changes or updates to a CustomControl always consider backwards compatibility. For example, if you rename an exposed property, the old property values stored via the property sheet won't be deserialized to your new property. \ No newline at end of file diff --git a/docs/CustomControls/index.md b/docs/CustomControls/index.md new file mode 100644 index 00000000..da2b3c60 --- /dev/null +++ b/docs/CustomControls/index.md @@ -0,0 +1,7 @@ +--- +title: CustomControls +nav_order: 3 +permalink: /CustomControls/ +--- + +# CustomControls \ No newline at end of file diff --git a/docs/Features/Control anchoring and docking.md b/docs/Features/Control anchoring and docking.md new file mode 100644 index 00000000..2ba373aa --- /dev/null +++ b/docs/Features/Control anchoring and docking.md @@ -0,0 +1,76 @@ +--- +title: Control Anchoring and Docking +parent: Features +nav_order: 2 +permalink: /Features/Anchoring-Docking/ +--- + +# Anchoring + +One of the new form designer features you see in twinBASIC is the 'Anchors' property: + +![image](Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png) + +Clicking the arrow on the left expands it to provide 4 options: + +![image](Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png) + +These control whether the position of each point relative to the borders of their parent form or control container are maintained when the form is resized. By default it behaves in the expected manner; the top and left stay the same, and the control is not resized or moved with the form unless you do this manually with code, typically in the `Form_Resize` event. These provide an alternative to handle sizing and moving automatically. + +If a control is anchored at all 4 positions, it will be resized in both dimensions along with the form: + +![image](Images/fddbffa9-2b71-47f5-b925-e67fc66b9e5c.png) + +As you can see, all anchor points were kept a constant distant from the edge, resulting in the control being resized. If you anchored only the Top, Left, and Bottom, it will be resized vertically, but not horizontally: + +![image](Images/3fa1cf2b-0af5-44ae-ae6a-3c0662f51f57.png) + +Right was not anchored to the edge, so it didn't move with the edge. + +If you remove the anchors to the Top and Left (False) but maintain the Right and Bottom anchors (True), the control will move with the Bottom and Right: + +![image](Images/0aeb25f6-d864-4ebb-a9f5-bbd7b5d242e8.png) + +The control stayed the same size, and because the Right and Bottom were anchored to the edge, they moved with the form, resulting in the whole control moving. + +### Control Containers + +The above examples illustrate how this works with controls directly on a Form. But what if they're inside a Frame or other control container? The anchors are relative to their parent, so resizing a Form won't resize or move a control inside a Frame unless the Frame is also anchored in a way that changes its size/position. + +For example, if a TextBox is anchored at all 4 points, inside a Frame anchored at all 4 points, then it will resize along with the Frame: + +![image](Images/4829696d-788b-40ee-bebd-5afa44477460.png) + +If we remove the Bottom anchor from the TextBox, but not the Frame, the Frame will be resize along the bottom, but the TextBox will not: + +![image](Images/bc9f3756-a14b-4ee7-b819-6822497b640a.png) + + +Using these 4 points you can automatically maintain a relative size, position, or both, without having to manually code any of it. + +{: .tip } +> Reminder, twinBASIC also adds `MinWidth`, `MinHeight`, `MaxWidth`, and `MaxHeight` properties to a Form, so those can also be automatically managed in combination with control anchors. You may want to set a minimum size so that controls do not disappear. + +# Docking + +Similar to anchoring but slightly different, tB also offers a 'Dock' property: + +![image](Images/4c8b881e-1216-4819-a558-d2ce20f47fcd.png) + +You might already be familiar with how a StatusBar control locks itself to the bottom of a form; that's the kind of positioning this property controls. A control can be docked on any side, and it will stay sized to the full width or height, and move with, that side of the Form or parent container. For example, a CommandButton with `vbDockBottom`: + +![image](Images/599a66ad-31d5-449f-bbf5-00963fe9aa2a.png) + +Besides the four sides, there's a final option: `vbDockFill`. This will have the control fill its entire parent area. This is most useful when used with a container such as a PictureBox or Frame control-- it will fill only that container when its a child of it, not the whole form. + +`vbDockFill` will exclude other docked controls, so you could for instance have one control with `vbDockRight` and another with `vbDockFill` that covers the rest of the Form or container while the first control stays in position on the right. + +### Multiple Controls + +As the end of the last section suggests, it's possible to dock more than one control to the same location, such as a CommandButton and TextBox docked to the bottom. The following example also shows a PictureBox control with the `vbDockRight` + `vbDockFill` example from above: + +![image](Images/80185a8d-2952-415f-bc02-ec3ddea89568.png) + +{: .tip } +> The order of two (or more) controls docked in the same position is determined by which was set first. Currently they can't be dragged to rearranged, but you can set the Dock property back to none, and re-do them in the desired order. + diff --git a/docs/Features/Images/014a1d28-30af-4a4d-8b9b-83ab6084f00a.png b/docs/Features/Images/014a1d28-30af-4a4d-8b9b-83ab6084f00a.png new file mode 100644 index 00000000..6b7433c3 Binary files /dev/null and b/docs/Features/Images/014a1d28-30af-4a4d-8b9b-83ab6084f00a.png differ diff --git a/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.png b/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.png new file mode 100644 index 00000000..67577afb Binary files /dev/null and b/docs/Features/Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.png differ diff --git a/docs/Features/Images/021f6cbf-acce-445d-ade7-3fcad0af4927.png b/docs/Features/Images/021f6cbf-acce-445d-ade7-3fcad0af4927.png new file mode 100644 index 00000000..2e436275 Binary files /dev/null and b/docs/Features/Images/021f6cbf-acce-445d-ade7-3fcad0af4927.png differ diff --git a/docs/Features/Images/0aeb25f6-d864-4ebb-a9f5-bbd7b5d242e8.png b/docs/Features/Images/0aeb25f6-d864-4ebb-a9f5-bbd7b5d242e8.png new file mode 100644 index 00000000..3ebd97a5 Binary files /dev/null and b/docs/Features/Images/0aeb25f6-d864-4ebb-a9f5-bbd7b5d242e8.png differ diff --git a/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png new file mode 100644 index 00000000..d3c4c95d Binary files /dev/null and b/docs/Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png differ diff --git a/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png new file mode 100644 index 00000000..62a5cc9c Binary files /dev/null and b/docs/Features/Images/351d0147-cad3-4e16-89e5-0a9e43496740.png differ diff --git a/docs/Features/Images/3fa1cf2b-0af5-44ae-ae6a-3c0662f51f57.png b/docs/Features/Images/3fa1cf2b-0af5-44ae-ae6a-3c0662f51f57.png new file mode 100644 index 00000000..7869a311 Binary files /dev/null and b/docs/Features/Images/3fa1cf2b-0af5-44ae-ae6a-3c0662f51f57.png differ diff --git a/docs/Features/Images/4829696d-788b-40ee-bebd-5afa44477460.png b/docs/Features/Images/4829696d-788b-40ee-bebd-5afa44477460.png new file mode 100644 index 00000000..adb2d424 Binary files /dev/null and b/docs/Features/Images/4829696d-788b-40ee-bebd-5afa44477460.png differ diff --git a/docs/Features/Images/4ad9c774-b31d-47d3-9963-6d99ac4f37bb.png b/docs/Features/Images/4ad9c774-b31d-47d3-9963-6d99ac4f37bb.png new file mode 100644 index 00000000..4dc57b9d Binary files /dev/null and b/docs/Features/Images/4ad9c774-b31d-47d3-9963-6d99ac4f37bb.png differ diff --git a/docs/Features/Images/4c4d2582-5c79-43bc-bd77-26cdfa49ed7f.png b/docs/Features/Images/4c4d2582-5c79-43bc-bd77-26cdfa49ed7f.png new file mode 100644 index 00000000..c74115a5 Binary files /dev/null and b/docs/Features/Images/4c4d2582-5c79-43bc-bd77-26cdfa49ed7f.png differ diff --git a/docs/Features/Images/4c8b881e-1216-4819-a558-d2ce20f47fcd.png b/docs/Features/Images/4c8b881e-1216-4819-a558-d2ce20f47fcd.png new file mode 100644 index 00000000..f755920b Binary files /dev/null and b/docs/Features/Images/4c8b881e-1216-4819-a558-d2ce20f47fcd.png differ diff --git a/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.png b/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.png new file mode 100644 index 00000000..c3fc0ec3 Binary files /dev/null and b/docs/Features/Images/4fc2bf99-2bec-4943-837d-21038d791574.png differ diff --git a/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png new file mode 100644 index 00000000..51e43e09 Binary files /dev/null and b/docs/Features/Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png differ diff --git a/docs/Features/Images/5951dab6-738e-4b63-83c4-3331ec6d36b9.png b/docs/Features/Images/5951dab6-738e-4b63-83c4-3331ec6d36b9.png new file mode 100644 index 00000000..f6fa45ea Binary files /dev/null and b/docs/Features/Images/5951dab6-738e-4b63-83c4-3331ec6d36b9.png differ diff --git a/docs/Features/Images/599a66ad-31d5-449f-bbf5-00963fe9aa2a.png b/docs/Features/Images/599a66ad-31d5-449f-bbf5-00963fe9aa2a.png new file mode 100644 index 00000000..43e2a473 Binary files /dev/null and b/docs/Features/Images/599a66ad-31d5-449f-bbf5-00963fe9aa2a.png differ diff --git a/docs/Features/Images/5fc60b7b-4f54-445c-8504-451019b7ec55.png b/docs/Features/Images/5fc60b7b-4f54-445c-8504-451019b7ec55.png new file mode 100644 index 00000000..b35551aa Binary files /dev/null and b/docs/Features/Images/5fc60b7b-4f54-445c-8504-451019b7ec55.png differ diff --git a/docs/Features/Images/80185a8d-2952-415f-bc02-ec3ddea89568.png b/docs/Features/Images/80185a8d-2952-415f-bc02-ec3ddea89568.png new file mode 100644 index 00000000..1da8a6b3 Binary files /dev/null and b/docs/Features/Images/80185a8d-2952-415f-bc02-ec3ddea89568.png differ diff --git a/docs/Features/Images/85f25aa2-abc8-4d42-8510-078f8ee4a324.png b/docs/Features/Images/85f25aa2-abc8-4d42-8510-078f8ee4a324.png new file mode 100644 index 00000000..9b9e83e9 Binary files /dev/null and b/docs/Features/Images/85f25aa2-abc8-4d42-8510-078f8ee4a324.png differ diff --git a/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png b/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png new file mode 100644 index 00000000..d8377044 Binary files /dev/null and b/docs/Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png differ diff --git a/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png new file mode 100644 index 00000000..226ce6a7 Binary files /dev/null and b/docs/Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png differ diff --git a/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png new file mode 100644 index 00000000..60fb9e4e Binary files /dev/null and b/docs/Features/Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png differ diff --git a/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png new file mode 100644 index 00000000..39531a40 Binary files /dev/null and b/docs/Features/Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png differ diff --git a/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png new file mode 100644 index 00000000..fda9b7fe Binary files /dev/null and b/docs/Features/Images/b26da59b-4e98-40b7-b97b-bb3cef4ca1d0.png differ diff --git a/docs/Features/Images/bc9f3756-a14b-4ee7-b819-6822497b640a.png b/docs/Features/Images/bc9f3756-a14b-4ee7-b819-6822497b640a.png new file mode 100644 index 00000000..85b5e1f5 Binary files /dev/null and b/docs/Features/Images/bc9f3756-a14b-4ee7-b819-6822497b640a.png differ diff --git a/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png new file mode 100644 index 00000000..7bd6d88c Binary files /dev/null and b/docs/Features/Images/d5dff8f5-c5fa-4620-ba11-430d06276b27.png differ diff --git a/docs/Features/Images/fafaloneIDEscreenshot1.png b/docs/Features/Images/fafaloneIDEscreenshot1.png new file mode 100644 index 00000000..91ccc889 Binary files /dev/null and b/docs/Features/Images/fafaloneIDEscreenshot1.png differ diff --git a/docs/Features/Images/fddbffa9-2b71-47f5-b925-e67fc66b9e5c.png b/docs/Features/Images/fddbffa9-2b71-47f5-b925-e67fc66b9e5c.png new file mode 100644 index 00000000..01f55a2f Binary files /dev/null and b/docs/Features/Images/fddbffa9-2b71-47f5-b925-e67fc66b9e5c.png differ diff --git a/docs/Features/Overview.md b/docs/Features/Overview.md new file mode 100644 index 00000000..351c54cc --- /dev/null +++ b/docs/Features/Overview.md @@ -0,0 +1,1440 @@ +--- +title: Overview +parent: Features +nav_order: 1 +permalink: /Features/Overview/ +--- + +# Overview + +This page is intended to list and briefly describe all new features that twinBASIC brings compared to VBx, and assumes existing familiarity with the principles of programming in the BASIC language. They are categorized into the following sections: + +* [Attributes](#attributes) +* [64bit Compilation](#64bit-compilation) +* [Language Syntax](#language-syntax) +* [Project Configuration](#project-configuration) +* [Standard Library Enhancement](#standard-library-enhancements) +* [GUI components](#gui-components) (e.g. controls and forms) +* [Design Experience and Compiler Features](#design-experience-and-compiler-features) + +# Attributes +Attributes have two major functions: they can act as instructions to compiler to influence how code is generated, or to annotate an element (Forms, Modules, Classes, Types, Enums, Declares, Subs/Functions, etc). Previously in VBx, these attributes, such as procedure description, hidden, default member, and others, were set via hidden text the IDE's editor didn't show you, configured via the Procedure Attributes dialog or some other places. In tB, these are all visible in the code editor. The legacy ones from VBx are supported for compatibility, but new attributes utilize the following syntax:\ +`[Attribute]` or `[Attribute(value)]`\ +Many new attributes enable the powerful additional language features twinBASIC provides, so some of the following items have their associated attributes included in their description, then general/miscellaneous ones will be described later on. + +# 64bit Compilation + +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`, e.g.:\ +`Public Declare PtrSafe Sub foo Lib "bar" (ByVal hWnd As LongPtr)` + +{: .important } +> 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. 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). 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). + +# Language Syntax + +## New data types +* `LongPtr` Meant primarily to handle pointers, `LongPtr` is a 4-byte (32 bits) signed integer in 32bit mode, and a signed 8-byte integer (64 bits) in 64bit mode. +* `LongLong` A signed 8-byte (64 bits) integer, ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Note that this type is available in both 32bit and 64bit mode (VBA restricts it to 64bit mode). +* `Decimal` In twinBASIC, `Decimal` is implementented as a full, regular data type, in addition to use within a `Variant`. This is a 16-byte (128 bits) type which holds a 12-byte (96 bits) integer with variable decimal point scaling and sign bit information. Values range from -79,228,162,514,264,337,593,543,950,335 to 79,228,162,514,264,337,593,543,950,335. +* All of the datatype management features also exist for these types: `DefDec`/`DefLngLng`/`DefLongPtr`, `CDec`/`CLngLng`/`CLongPtr`, and `vbDecimal`/`vbLongLong`/`vbLongPtr` constants for type checking. + +## Interfaces and coclasses + +### Defining interfaces +twinBASIC supports defining COM interfaces using BASIC syntax, rather than needing an type library with IDL and C++. These are only supported in .twin files, not in legacy .bas or .cls files. They must appear *before* the `Class` or `Module` statement, and will always have a project-wide scope. the The generic form for this is as follows: + +``` +[InterfaceId ("00000000-0000-0000-0000-000000000000")] +** +Interface Extends + ** + + ** + + ... +End Interface +``` +Methods can be any of the following: `Sub`, `Function`, `Property Get`, `Property Let`, or `Property Set`, with arguments following the standard syntax, and with the standard attributes available. These cannot be modified with `Public/Private/Friend`. `End ` is not used, as these are prototype definitions only. + +Available attributes for interfaces currently include: +* `[Description("text")]` - Provides a description in information popups, and is exported as a `helpstring` attribute in the type library (if applicable). + +* `[Hidden]` - Hides the interface from certain Intellisense and other lists. + +* `[Restricted]` - Restricts the interface methods from being called in most contexts. + +* `[OleAutomation(True/False)]` - Controls whether this attribute is applied in the typelibrary. This attribute is set to **True** by default. + +* `[ComImport]` - Specifies that an interface is an import from an external COM library, for instance, the Windows shell. + +* `[COMExtensible(True/False)]` - Specifies whether new members added at runtime can be called by name through an interface implementing IDispatch. This attribute is set to **False** by default. + +Available attributes for methods currently include: + +* `[Description("text")]` - See above. + +* `[PreserveSig]` - For COM interfaces, normally methods return an HRESULT that the language hides from you. The `[ PreserveSig ]` attribute overrides this behavior and defines the function exactly as you provide. This is neccessary if you need to define it as returning something other than a 4-byte `Long`, or want to handle the result yourself, bypassing the normal runtime error raised if the return value is negative (this is helpful when a negative value indicates an expected, acceptable failure, rather than a true error, like when an enum interface is out of items). + +* `[DispId(number)]` - Defines a dispatch ID associated with the method. + +#### Example + +``` +[InterfaceId("E7064791-0E4A-425B-8C8F-08802AAFEE61")] +[Description("Defines the IFoo interface")] +[OleAutomation(False)] +Interface IFoo Extends IUnknown + Sub MySub(Arg1 As Long) + Function Clone() As IFoo + [PreserveSig] + Function MyFunc([TypeHint(MyEnum)] Arg1 As Variant) As Boolean +End Interface +``` +(Where MyEnum is a standard `Enum ... End Enum` block. + + +### Defining coclasses +In addition to interfaces, twinBASIC also allows defining coclasses -- creatable classes that implement one or more defined interfaces. Like interfaces, these too must be in .twin files and not legacy .bas/.cls files, and must appear prior to the `Class` or `Module` statement. The generic form is: + +``` +[CoClassId("00000000-0000-0000-0000-000000000000")] +** +CoClass + [Default] Interface + *[Default, Source] Interface * + ** +End CoClass +``` + +Each coclass must specify at least one interface but may have several more. It can optionally mark an interface as default or a source. It is typical and highly recommended that an interface be marked with `[Default]` attribute and in cases where it has events to also specify `[Default, Source]` to indicate the default interface used for events. Each represents a contract that the class will provide an implementation of the given interface. Note that at this time, twinBASIC does not yet support defining `dispinterface` interfaces (aka, dispatch-only interface) the usual form of source interfaces for events. + +The attributes available for coclasses are as follows: +* `[Description("text")]` - Provides a description in info popups and other places. +* `[ComCreatable(True/False)]` - Indicates that this coclass can be created with the `New` keyword. This is *True* by default. +* `[AppObject]` - Indicates the class is part of the global namespace. You should not include this attribute without a full understanding of the meaning. +* `[Hidden]` - Hides the coclass from appearing in certain places. +* `[CoClassCustomConstructor("fully qualified path to factory method")]` - Allows custom logic for creating and returning a new instance of the coclass' implementation. + +#### Example + +``` +[CoClassId("52112FA1-FBE4-11CA-B5DD-0020AFE7292D")] +CoClass Foo + [Default] Interface IFoo + Interface IBar +End CoClass +``` +Where `IFoo` and `IBar` are interface defined with the `Interface` syntax described earlier. + +For custom constructor, you should provide a method on a module to create the instance. Here's an example of how this can be achieved. + +``` +[InterfaceId("016BC30A-A8E0-4AAF-93AE-13BD838A149E"))] +Public Interface IFoo + Sub Foo() +End Interface + +[InterfaceId("2A20E655-30A4-4534-86BC-6A7E281C425D")] +Public Interface IBar + Sub Bar() +End Interface + +[CoClassId("7980D953-10BF-478C-93BB-DD0093315D96")] +[CoClassCustomConstructor("FooFactory.CreateFoo")] +[COMCreatable(True)] +Public CoClass Foo + [Default] Interface IFoo + Interface IBar +End CoClass + +' The implementation do not have to be exposed. The coclass is a sufficient description +' and we should implement the interfaces that the coclass exposes. +Private Class FooImpl + Implements IFoo + Implements IBar + + Public Sub Foo() Implements IFoo.Foo + Debug.Print "Foo ran" + End Sub + + Public Sub Bar() Implements IBar.Bar + Debug.Print "Bar ran" + End Sub +End Class + +Public Module FooFactory + ' The signature must be "preserved", returning a HRESULT + ' and the new instance via the "out" parameter. + ' Note that we new up the FooImpl but return the Foo coclass. + Public Function CreateFoo(ByRef RHS As Foo) As Long + Set RHS = New FooImpl + Return 0 ' S_OK + End Function +End Module + +Public Module Test + Public Sub DoIt() + Dim MyFoo As Foo + ' create a new instance of coclass Foo + ' this implicilty calls the custom constructor + ' in the FooFactory. + Set MyFoo = New Foo + MyFoo.Foo + End Sub +End Module +``` + +### Enhancements to `Implements` +* `Implements` in twinBASIC is allowed on inherited interfaces-- for instance, if you have `Interface IFoo2 Extends IFoo`, you then use `Implements IFoo2` in a class, where in VBx this would not be allowed. You'll need to provide methods for all inherited interfaces (besides `IDispatch` and `IUnknown`). The class will mark all interfaces as available-- you don't need a separate statement for `IFoo`, it will be passed through `Set` statements (and their underlying `QueryInterface` calls) automatically. + +* If you have an interface multiple others extend from, you can write multiple implementations, or specify one implementation for all. For example: + + ``` vb + IOleWindow_GetWindow() As LongPtr _ + Implements IOleWindow.GetWindow, IShellBrowser.GetWindow, IShellView2.GetWindow + ``` + +* `Implements` allowed on interfaces with 'As Any' parameters: In VBx, you'd get an error if you attempted to use any interface containing a member with an `As Any` argument. With twinBASIC, this is allowed if you substitute `As LongPtr` for `As Any`, for example: + + ``` vb + Interface IFoo Extends IUnknown + Sub Bar(ppv As Any) + End Interface + + Class MyClass + Implements IFoo + + Private Sub IFoo_Bar(ppv As LongPtr) Implements IFoo.Bar + + End Sub + ``` + +### `Implements Via` for basic inheritance and `Inherits` for complete inheritance and full Object-Oriented Programming (OOP) + +#### `Implements Via` + +tB allows simple inheritance among classes. For example, if you have class cVehicle which implements IVehicle containing method Honk, you could create child classes like cCar or cTruck, which inherit the methods of the original, so you could call cCar.Honk without writing a separate implementation. Here's what this looks like as code: + +![image](Images/b0724fe2-636d-47db-a8fc-531a585ddaf9.png) + +You can see that the Honk method is only implemented by the parent class, then called from the child class when you click the CodeLens button to run the sub in place from the IDE. + +#### `Inherits` + +This is a more robust option for full inheritance and OOP. It supports `Protected` methods and variables that are accessible to derived classes but not outside callers, `Overridable` and `Overrides` syntax, multiple inheritance, and explicit base class constructors. Sample 23 demonstrates this: + +Starting with a base class, + +``` vb +Private Class Animal + Protected _name As String + Protected _dob As Date ' date of birth + + Public Event Spoke(ByVal sound As String) + + Public Sub New(name As String, dob As Date) + _name = name + _dob = dob + End Sub + + Public Property Get Name() As String + Name = _name + End Property + + Public Property Get DOB() As Date + DOB = _dob + End Property + + ' Age in whole years based on DOB and today's date + Public Function AgeYears() As Long + Dim y As Long + y = DateDiff("yyyy", _dob, Date) + If DateSerial(Year(Date), Month(_dob), Day(_dob)) > Date Then y = y - 1 + AgeYears = y + End Function + + Public Sub Speak() + Dim s As String + s = GetSound() + RaiseEvent Spoke(s) + Debug.Print _name & " says: " & s + End Sub + + ' --- Overridable hook for derived classes --- + Protected Overridable Function GetSound() As String + GetSound = "" + End Function +End Class +``` + +others can inherit: + +``` vb +' ===== Derived: Dog ===== +Private Class Dog + Inherits Animal + + Protected _breed As String + + Public Sub New(name As String, dob As Date, breed As String) + Animal.New(name, dob) ' we can explicitly call base constructors from within our constructor + _breed = breed + End Sub + + Public Property Get Breed() As String + Breed = _breed + End Property + + ' Override: + Protected Overridable Function GetSound() As String Overrides Animal.GetSound + GetSound = "woof" + End Function +End Class + +' ===== Further derived: GuardDog (Dog → GuardDog) ===== +Private Class GuardDog + Inherits Dog + + Protected _onDuty As Boolean + + Public Sub New(name As String, dob As Date, breed As String) + Dog.New(name, dob, breed) ' we can explicitly call base constructors from within our constructor + _onDuty = True + End Sub + + Public Property Get OnDuty() As Boolean + OnDuty = _onDuty + End Property + Public Property Let OnDuty(ByVal v As Boolean) + _onDuty = v + End Property + + ' Multi-level override (overriding Dog's override): + Protected Function GetSound() As String Overrides Dog.GetSound + If _onDuty Then + GetSound = "WOOF!" + Else + GetSound = "woof" + End If + End Function +End Class +``` + +This is just an excerpt, see the full Sample 23 for additional classes, usage, and information about inheritance in twinBASIC. + + +## Delegate types for Call By Pointer + +There is native support for calling a function by pointer, by way of `Delegate` syntax. A delegate in twinBASIC is a function pointer type that's compatible with LongPtr. `AddressOf` returns a delegate type, that's also backwards compatible with `LongPtr`. + +The syntax looks like this: + +``` vb + Private Delegate Function Delegate1 (ByVal A As Long, ByVal B As Long) As Long + + Private Sub Command1_Click() + Dim myDelegate As Delegate1 = AddressOf Addition + MsgBox "Answer: " & myDelegate(5, 6) + End Sub + + Public Function Addition(ByVal A As Long, ByVal B As Long) As Long + Return A + B + End Function +``` + +The delegate type can also be used in interface/API declarations and as members of a User-defined type, for example, the `ChooseColor` API: + +``` vb +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 'Delegate function pointer type instead of LongPtr + lpTemplateName As LongPtr +End Type +``` + +If you already have code assigning a `Long`/`LongPtr` to the `lpfnHook` member, it will continue to work normally, but now you can also have the type safety benefits of setting it to a method matching the Delegate: + +``` vb +Dim tCC As CHOOSECOLOR +tCC.lpfnHook = AddressOf ChooseColorHookProc + +'... + +Public Function ChooseColorHookProc(ByVal hwnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr + +End Function +``` + + +## Static linking of OBJ and LIB files + +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, example from the sqlite sample: + +``` vb +#If Win64 Then + Import Library "/Miscellaneous/sqlite3_64.obj" As SQLITE3 Link "stdlib", "kernel32" +#Else + Import Library "/Miscellaneous/sqlite3_32.obj" As SQLITE3 Link "stdlib", "kernel32" +#End If + +Generically: + + Import Libary "Relative resource path" As NAMESPACE Link "dependency1", "dependency2", '... +``` + +After that, you can use NAMESPACE in place of a DLL name, inside class/module declares: + +``` vb +' Compiled sqlite-amalgamation-3440200 (v3.44.2) +' using cmdline (MSVC): cl /c /Gw /Gy /GS- /DSQLITE_OMIT_SEH sqlite3.c +#If Win64 Then + Import Library "/Miscellaneous/sqlite3_64.obj" As SQLITE3 Link "stdlib", "kernel32" +#Else + Import Library "/Miscellaneous/sqlite3_32.obj" As SQLITE3 Link "stdlib", "kernel32" +#End If + +Module MainModule + + Declare PtrSafe Function sqlite3_open CDecl Lib SQLITE3 (ByVal filename As String, ByRef ppDb As LongPtr) As Long + 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 +'... +``` + +{: .note } +>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`. + +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. + +## `Emit()` and Naked functions to insert assembly directly into exe/dll + +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. + +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): + +``` vb +Public Function InlineInterlockedIncrement CDecl Naked(Addend As Long) As Long +#If Win64 Then + Emit(&Hb8, &H01, &H00, &H00, &H00) ' mov eax,0x1 + Emit(&Hf0, &H0f, &Hc1, &H41, &H00) ' lock xadd DWORD PTR [rcx+0x4],eax + Emit(&Hff, &Hc0) ' inc eax + Emit(&Hc3) ' ret +#Else + Emit(&H8b, &H4c, &H24, &H04) ' mov ecx, DWORD PTR _Addend$[esp-4] + Emit(&Hb8, &H01, &H00, &H00, &H00) ' mov eax, 1 + Emit(&Hf0, &H0f, &Hc1, &H01) ' lock xadd DWORD PTR [ecx], eax + Emit(&H40) ' inc eax + Emit(&Hc3) ' ret 0 +#End If +End Function +``` +(Note: The `CDecl` calling convention is optional; you can write x86 assembly using `_stdcall` and simply omit the notation.) + +## Type Inference + +Variables can now be declared `As Any` and their type will be inferred, similar to C++'s `auto`.\ +`Dim x As Any = 5&` would result in x being a `Long`. + +This is only for the `Dim` statement; arguments cannot be `As Any` except in API declarations. + +## New operators +* Bitshift operators ``<<`` and ``>>`` perform left-shift and right-shift operations on a numeric variable. Note that shifts beyond available size result in 0, not wrapping. + +* `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** + ``` vb + 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(vbNullPtr) + End Sub + ``` + +Additionally, while not strictly new syntax, twinBASIC also adds support for `ByVal Nothing`, to override a `ByRef ` argument and pass a null pointer there. + +* Short-circuit conditional operators `OrElse` and `AndAlso`. With the regular `Or` and `And` statements, both sides are evaluated, even when not necessary. With a short circuit operator, if the condition is resolved by the first side, the other side is not evaluated. So if you have: +`If Condition1 OrElse Condition2 Then`, if Condition1 is `True`, then `Condition2` will not be evaluated, and any code called by it will not run. + +* Short-circuit `If()` operator with syntax identical to the tradition `IIf`. This has the additional benefit of not converting variables into a `Variant` if they're the same type; i.e. `If(condition, Long, Long)` the `Long` variables will never become a `Variant`. + +* New assignment operators: `+= -= /= *= ^= &= <<= >>=` + + These are the equivalent of `var = var (operand) (var2)`. So `i += 1` is the equivalent of `i = i + 1`. + +* `IsNot` operator: The logical opposite of the *Is* operator for testing object equivalence. For example, instead of `If (object Is Nothing) = False` you could now write `If object IsNot Nothing Then`. + +## New literals notation + +### Binary literals +In addition to `&H` for hexadecimal literals and `&O` for octal notation, twinBASIC also provides `&B` for binary notation. For example, `Dim b As Long = &B010110` is valid syntax, and b = 22. + +### Digit grouping +The `&H`, `&O`, and `&B` literals can all be grouped using an underscore, for example, grouping a `Long` by it's constituent binary byte groups: `&B10110101_10100011_10000011_01101110`, or grouping a `LongLong` as two `Long` groups: `&H01234567_89ABCDEF`. + +## Thread safety/multithreading support +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. + +### Example + +In a new Standard EXE project, add a CommandButton and TextBox to your form: + +``` vb +Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long + +Private Declare PtrSafe Function CreateThread Lib "kernel32" ( _ + ByRef lpThreadAttributes As Any, _ + ByVal dwStackSize As Long, _ + ByVal lpStartAddress As LongPtr, _ + ByRef lpParameter As Any, _ + ByVal dwCreationFlags As Long, _ + ByRef lpThreadId As Long) As LongPtr + +Private Declare PtrSafe Function WaitForSingleObject Lib "kernel32" ( _ + ByVal hHandle As LongPtr, _ + ByVal dwMilliseconds As Long) As Long + + + +Private Const INFINITE = -1& + +Private Sub Command1_Click() Handles Command1.Click + Dim lTID As Long + Dim lCurTID As Long + Dim hThreadNew As LongPtr + lCurTID = GetCurrentThreadId() + hThreadNew = CreateThread(ByVal 0, 0, AddressOf TestThread, ByVal 0, 0, lTID) + Text1.Text = "Thread " & lCurTID & " is waiting on thread " & lTID + Dim hr As Long + hr = WaitForSingleObject(hThreadNew, 30000&) 'Wait 30s as a default. You can use INFINITE instead if you never want to time out. + Text1.Text = "Wait end code " & CStr(hr) +End Sub + +Public Sub TestThread() + MsgBox "Hello thread" +End Sub +``` +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. + + +## 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: + +``` vb +Dim foo1 As New CFoo +Dim lpfn As LongPtr = AddressOf foo1.bar +``` + +## Enhanced pointer functionality + +### `CType(Of )` +The `CType(Of )` 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. + +Consider the following UDTs: + +``` vb +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 codes examples work to manipulate the pointers: + +``` vb +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`. + +``` vb +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` + +``` vb +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 +``` + +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. + +### Substitute pointers for UDTs + +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: + +``` vb +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, '...) +``` + + +## `Len/LenB(Of )` 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)`. + +## Overloading + +twinBASIC supports overloading in two ways: + +### Overloading by type of argument +The following Subs are valid together in a module/class/etc: + +``` vb +Sub foo(bar As Integer) +'... +End Sub + +Sub foo(bar As Long) +'... +End Sub + +Sub foo(bar As Double) +'... +End Sub +``` +The compiler will automatically pick which one is called by the data type. + +### Overloading by number of arguments +In addition to the above, you could also add the following: + +``` vb +Sub Foo(bar1 As Integer) +'... +End Sub +Sub Foo(bar1 As Integer, bar2 As Integer) +'... +End Sub +``` +The compiler will automatically pick which one is called by the number and/or types of arguments. + +## Inline variable initialization +You can now set initial values for variables inline, without needing a line-continuation character. + +**Examples** + +``` vb +Dim i As Long = 1 +Dim foo As Boolean = bar() +Dim arr As Variant = Array(1, 2, 3) +Dim strArr(2) As String = Array("a", "b", "c") +Dim cMC As cMyClass = New cMyClass(customConstructorArgs) +``` + +## Inline variable declaration for `For` +You now no longer need a separate `Dim` statement for counter variables: + +``` vb +For i As Long = 0 To 10 + '... +Next +``` +is now valid syntax. You can use any type, not just `Long`. + +## Generics +Generics have basic support in methods and classes. + +``` vb +Public Function TCast(Of T)(ByRef Expression As T) As T + Return Expression +End Function +``` +Which could be used e.g. to return a `Date` typed variable with `TCast(Of Date)("2021-01-01")` + +A Class generic allows the type in methods throughout the class. The following example shows this to make a generic List class: + +``` +[COMCreatable(False)] +Class List(Of T) + Private src() As T + Private c As Long + Sub New(p() As T) + src = p + End Sub + [DefaultMember] + Function GetAt(ByVal idx As Long) As T + Return src(idx) + End Function + Public Property Get Count() As Long + Return c + End Property +End Class +``` + +This could then be used as follows: + +``` vb +Private Sub TestListGenericClass() + Dim names As List(Of String) = New List(Of String)(Array("John", "Smith", "Kane", "Tessa", "Yoland", "Royce", "Samuel")) + Dim s As String = names(0) + Debug.Print s +End Sub +``` + +## Enhancements to API/method declarations +### `DeclareWide` +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: + +``` vb +Public Declare PtrSafe Sub FooW Lib "some.dll" (ByVal bar As LongPtr) +Public DeclareWide PtrSafe Sub Foo Lib "some.dll" Alias "FooW" (ByVal bar As String) +``` +Both represent a fully Unicode operation, but the allows direct use of the `String` datatype without requiring the use of `StrPtr` to prevent conversion. + +{: .warning } +> 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`. + +### `CDecl` support +The cdecl calling convention is supported both for API declares and methods in your code. This includes DLL exports in standard DLLs. Examples: + +``` vb +Private DeclareWide PtrSafe Function _wtoi64 CDecl Lib "msvcrt" (ByVal psz As String) As LongLong` +``` + +``` +[ DllExport ] +Public Function MyExportedFunction CDecl(foo As Long, Bar As Long) As Long +``` + +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): + +``` vb +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 _ +) + +Public Sub CallMe() + Dim z() As Long + Dim i As Long + Dim s As String + + ReDim z(10) As Long + For i = 0 To UBound(z) + z(i) = Int(Rnd * 1000) + Next i + qsort z(0), UBound(z) + 1, LenB(z(0)), AddressOf Comparator + For i = 0 To UBound(z) + s = s & CStr(z(i)) & vbNewLine + Next i + MsgBox s +End Sub + +Private Function Comparator CDecl( _ + ByRef a As Long, _ + ByRef b As Long _ +) As Long + Comparator = a - b +End Function +``` + +### Variadic Arguments support +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. + +Using the [given C/C++ prototype](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfw): + +``` cpp +int WINAPIV wsprintfW( + [out] LPWSTR unnamedParam1, + [in] LPCWSTR unnamedParam2, + ... +); +``` + +The twinBASIC declaration and function using it can be written as shown: + +``` vb +Private DeclareWide PtrSafe Function wsprintfW CDecl _ +Lib "user32" ( _ + ByVal buf As String, _ + ByVal format As String, _ + ByVal ParamArray args As Any() _ +) As Long + +Private Sub Test() + Dim buf As String = Space(1024) + wsprintfW(buf, "%d %d %d", 1, 2, 3) + MsgBox buf +End Sub +``` + +For functions which contain the `va_list` type as part of their arguments the ParamArray declaration must be `ByRef` + +### `[PreserveSig]` +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. Example: + +``` vb +Public Declare PtrSafe Function SHGetDesktopFolder Lib "shell32" (ppshf As IShellFolder) As Long +``` +can be rewritten as +``` +[PreserveSig(False)] +Public Declare PtrSafe Function SHGetDesktopFolder Lib "shell32" () As IShellFolder` +``` + + +## Loop control +The following new statements are available for controlling the procession of loops: + +* `Continue For` - Proceed to the next iteration (or end) of `For` loop. +* `Continue While` - Proceed to the next iteration (or end) of `While` loop. +* `Continue Do` - Proceed to the next iteration of `Do` loop. +* `Exit While` - Exit a `While` loop immediately. + +## `Return` syntax for functions. +You can now combine assigning a return value and exiting a function into a single statement like many other languages allow. This is accomplished with the `Return` keyword: + +``` vb +Private Function Foo() As Long +Dim i As Long = 1 +If i Then + Return i +End If +End Function +``` +this is the equivalent of + +``` vb +Private Function Foo() As Long +Dim i As Long = 1 +If i Then + Foo = i + Exit Function +End If +End Function +``` +`Return` can be used for objects as well. It is currently only valid with a value specified and within a function; you cannot use `Return` without anything after it in a sub. + +## New class member handler syntax +You can now separate the name of method from the class member it applies to. + +### `Handles` for events +For events events on Forms, UserControls, and event-raising objects, you can define any method as the handler, rather than need to name it as `Object_Event()`, by following it with `Handles Object.Event`. For example, in a form, instead of `Private Sub Form_Load()` you could handle the `Load` event with `Private Sub OnLoad() Handles Form.Load`. + +### `Implements` for interfaces +Similar to the above, for forms/UCs/classes that use `Implements`, you can use `Sub Bar() Implements IFoo.Bar`. Note that you can specify more than one implemented method; for more information, see the Enhancements to Implements subsection of the Interfaces and Coclasses section detailing the new in-language syntax for defining these. + +{: .note } +> These are opt-in and optional\ +> For compatibility, twinBASIC will always continue to support the traditional syntax for event handling and Implements, and you're not required to use this new syntax (or *any* of the additions described in this article). Whether or not automatically created prototypes use this syntax is controlled via IDE Options: "IDE: Use new handles/implements syntax". + +## Enhancements to user-defined types (UDTs) + +### Procedures and events + +You can now place methods inside UDTs, as well as API declarations. With APIs, if the first parameter is named `Me` and is the same type as the UDT, it's treated as an implicit member call, + +``` vb +Type HWND + Value As LongPtr ' the raw HWND + Public DeclareWide PtrSafe Function BringWindowToTop Lib "user32" (ByVal Me As HWND) As Long +End Type +'... +myHwnd.BringWindowToTop() +``` + +There's also associated events, including a constructor and destructor that make it possible to create lightweight objects, like a C++ class; +``` vb +Type myType + a As Long + + Private Sub Type_Initialize() + ' NOTE: currently you can only access the UDT members using the "Me." prefix + End Sub + + Private Sub Type_Assignment(ByVal RHS As Variant) ' TIP: You can change the RHS type, and you can define multiple assignment functions + ' NOTE: currently you can only access the UDT members using the "Me." prefix + End Sub + + Private Function Type_Conversion() As Variant ' TIP: you can change the return type here, and you can define multiple conversion functions + ' NOTE: currently you can only access the UDT members using the "Me." prefix + End Function + + Private Function Type_DebugView() As String + ' NOTE: currently you can only access the UDT members using the "Me." prefix + End Function + + Private Sub Type_Terminate() + ' NOTE: currently you can only access the UDT members using the "Me." prefix + End Sub + +End Type +``` + +UDTs of these types are still stack allocated structs that can be used with standard Win32 APIs. + + +### Custom UDT packing +If you've done extensive work with the Windows API, every so often you'll come across user-defined types that have an extraneous member added called pad, padding, reserved, etc, that doesn't appear in the documentation for that type. This is the result of the UDT applying packing rules different from the default. By default, UDTs have hidden spacing bytes that make their largest sized member appear at a multiple of it's size, and making the entire UDT be a multiple of that size. Consider the following UDT: +``` vb +Private Type MyUDT + x As Integer + y As Long + z As Integer +End Type +Private t As MyUDT +``` +If you ask for `Len(t)`, you get 8-- the sum of 2x2-byte Integers and 1 4-byte Long. But if you ask for `LenB(t)`, you get 12. This is because the largest size type is 4, so that's the packing alignment number. Each Long must appear at a multiple of 4 bytes, so 2 byte of hidden padding is inserted between x and y. You can see this for yourself by checking `VarPtr(t.y) - VarPtr(t)`. This gives you the starting offset of `y`-- which is 4, not 2 like you'd get if it immediately followed `x`. Finally, with the hidden 2 bytes, we're now up to 10 bytes. But the total UDT size must be a multiple of 4, so 2 more hidden bytes are added on the end.\ +Some API UDTs will look like `MyUDT` is correct, but you'll see it defined in VBx as 2 Longs-- which gets the required 8 bytes, with some special handling for the first member. If you refer back to the original C/C++ header, you'll find, for this situation, something like `#include ` or `#pragma pack(push,1)` somewhere before the UDT. This manually alters the packing rule to insert no hidden bytes anywhere.\ +In twinBASIC, instead of two Longs and having to worry about getting the first one right when it's not an Integer, you can use the original definition with: +``` +[PackingAlignment(1)] +Private Type MyUDT + x As Integer + y As Long + z As Integer +End Type +Private t As MyUDT +``` +You'll now find that both `Len(t)` and `LenB(t)` are 8. **NOTE:** Alignment, not packing alignment, is not set this way-- specifying 16 would not get you a 16-byte structure for `t`. twinBASIC does not currently have an equivalent for `__declspec_align(n)`, but such a feature is planned. This is very, very rare outside kernel mode programming. + +## Block and inline comments + +You can now use `/* */` syntax. For example, `Sub Foo(bar As Long /* out */)` or: + +```c +/* +Everything here is +a comment until: +*/ +``` + + +## Destructuring assignment support for arrays +This feature allows you to assign the contents of an array to multiple variables in a single line: + +``` vb + Dim a As Long, b As Long, c As Long + Dim d(2) As Long + d(0) = 1 + d(1) = 2 + d(2) = 3 + Array(a, b, c) = d + Debug.Print a, b, c +``` + +This would print `1 2 3`. You could also assign multiple variables at once like this and get the same result: + +``` vb + Dim a As Long, b As Long, c As Long + Array(a, b, c) = Array(1, 2, 3) + Debug.Print a, b, c +``` + +You can now also do assignments like this: + +``` vb + Dim a As Long = 9 + Dim b As Long = 7 + Dim c() As Long = Array(a, b) + Debug.Print c(1), UBound(c) +``` + +Which prints `7 1`. + + +## Direct access to COM error handling +You can retrieve the last `HRESULT` to a COM interface call via `Err.LastHResult`; these are usually hidden and mapped to internal errors-- everything in a COM interface normally called a `Sub` is actually an `HRESULT`-returning function. + +More importantly, you can now **set** the `HRESULT` in interface implementations with `Err.ReturnHResult`. This was a critical missing feature for which sometimes Err.Raise would work, but mostly programmers resorted to complicated vtable-swapping code to redirect to a standard module function. For instance you can now return `S_FALSE` where expected with `Err.ReturnHResult = S_FALSE`. + +## Module-level definitions not limited to top +It's now possible to insert module-level code in between methods or properties. Where previously all `Declare` statements, `Enum`, `Type`, etc had to appear prior to the first `Sub/Function/Property`, the following would now be valid: + +``` vb +Private Const foo = "foo" +Sub SomeMethod() +'... +End Sub +Private Const bar = "bar" +Sub SomeOtherMethod() +'... +End Sub +``` + +## Preset methods for code part names +The following can be used and what they represent will be automatically inserted as a `String`: + +* `CurrentComponentName`, e.g. "Form1" +* `CurrentProcedureName`, e.g. "Foo" when in `Sub Foo()` +* `CurrentProjectName`, +* `CurrentSourceFile` +* `CurrentComponentCLSID` + + +## Removal of limits on line continuations, procedure size, etc. +twinBASIC imposes no artificial limitations on those, number of controls on a form, module size, and more. + +## Parameterized class constructors. +Classes now support a `New` sub with ability to add arguments, called as the class is constructed prior to the `Class_Initialize` event. For example a class can have: + +``` +[ComCreatable(False)] +Class MyClass +Private MyClassVar As Long +Sub New(Value As Long) +MyClassVar = Value +End Sub +End Class +``` + +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. + +## `Private`/`Public` modifiers for modules and classes +A private module or class won't have it's members entered into the type library in an ActiveX project. + +## `ReadOnly` variables +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. + +## Exported Functions and Variables +It's possible to export a function or variable from standard modules, including with CDecl, e.g. + +``` +[DllExport] +Public Const MyExportedSymbol As Long = &H00000001 + +[DllExport] +Public Function MyExportedFunction(ByVal arg As Long) As Long + +[DllExport] +Public Function MyCDeclExport CDecl(ByVal arg As Long) +``` + +This is primary used to create Standard DLLs (see next section), but this functionality is also available in Standard EXE and other compiled project types. + +# Project Configuration +## Built in support for making Standard DLLs +While it was possible to accomplish this via hacks previously, tB offers it as a built in project type. You can choose this project type at startup, then you simply need to mark functions with `[DllExport]` when you want them exported. The name will be used as-is, it will not be mangled. The `CDecl` calling convention is supported with the normal syntax, e.g. `Public Function foo CDecl(bar As Long) As Long`.\ +Standard DLLs in twinBASIC can still specify a startup point; each export will then check if this code has run yet, and if not, run it. + +## Built in support for making Console Applications +This project type allows making a true console project rather than a GUI project. Helpfully, it will also add a default `Console` class for reading/writing console IO and provided debug console. + +## Built in support for easily making services. +tB has a services package (WinServicesLib) that makes creating full featured true services a breeze. It simplifies use of MESSAGETABLE resources, multiple services per exe, named pipes for IPC, and more. See samples 21-22. + +## Built in support for making Kernel-Mode Drivers. +Kernel mode drivers can only access a very limited subset of the API, and can't call usermode DLLs like a runtime. So it would typically require elaborate hacks and dramatically limit what you could do in prior BASIC products, if possible at all. And of course, there's no WOW64 layer for kernel mode, so tB is the first BASIC product to support making drivers for 64bit Windows. This is controlled by the 'Project: Native subsystem' option, as well as the following two features. + +## Built in support for overriding entry point. +BASIC applications typically have a hidden entry point that is the first to run, before `Sub Main` or the startup form's `Form_Load`. This sets up features of the app like initializing COM. twinBASIC supports overriding this and setting one of your own procedures as the true entry point. This is mostly useful for kernel mode projects, which must have a specific kind of entry point and can't call the normal APIs in the default. But there are other reasons you might want to use this option, but be warned: Many things will break in a normal application if you don't do the initialization procedures yourself or understand precisely what you can't use. + +## Place API declares in the IAT +tB has the option to put all API declares in the import address table rather than call them at runtime via `LoadLibrary/GetProcAddress` like VBx (which puts TLB-declared APIs in the import table; tB replicates this too but further provides an option for in-project declares). + +This has a small performance advantage in that it's loaded and bound at startup rather than on the first call, but the primary use is for kernel mode, which cannot call `LoadLibrary` and other user mode APIs to use late binding. + + +## Register ActiveX builds to `HKEY_LOCAL_MACHINE` or `HKEY_CURRENT_USER` option. +While modern applications use `HKEY_CURRENT_USER`, for VBx compatibility components must be registered to `HKEY_LOCAL_MACHINE`. Note that this requires running as admin when registering. + +## Registration at build time is optional +tB provides the Project: Register DLL after build option so you can disable automatic registration, if for example you wanted to move the file first. + +# Misc Attributes +The following attributes are also available but haven't been described above: + +* `[Description("text")]` attribute for APIs, UDTs , and Consts that are shown in popups when you hover over uses of them and in VBx object browser. Additionally, this attribute can be used for `Module` or `Class` to describe the module/class itself, and if a class represents a creatable control, it will often be used in component lists to describe the control, as it's exported as the `helpstring` attribute at the class level too. +* `[RunAfterBuild]` attribute-- you can specify a function that runs after your exe is built (there's `App.LastBuildPath` to know where it is if you're e.g. signing the exe). +* Per-class/module and Per-procedure `[IntegerOverflowChecks(False)]`, `[FloatingPointErrorChecks(False)]` and `[ArrayBoundsChecks(False)]` attributes to disable those checks on performance-critical routines while leaving them generally in place. +* Constant function folding. You can specify a `[ConstantFoldable]` attribute for functions where when called with non-variable input, will be computed at compile time, rather than runtime. For example, a function to converted string literals to ANSI. The result would never change, so the resulting ANSI string is stored, rather than recomputing every run. +* `[Unimplemented]` attribute for methods allows showing a compiler warning about it being unimplemented wherever it's called. You can upgrade it to error too. +* `[SetDllDirectory(True/False)]` attribute to allow an explicitly loaded DLL to load it's own dependencies from it's load path. Also has the effect of allowing searching the app path for the DLLs in the base app's declare statements. It can be used per-declare or within a module. +* `[EnumId("GUID")]` specifies a GUID to be associated with an enum in type libraries. +* `[TypeHint()]` attribute allows populating Intellisense with an enum for types other than `Long`. +* `[CompileIf(condition)]` method attribute for more advanced control over conditional compilation. +* `[DebugOnly]` for a Sub/Function will exclude calls to it from the build. +* `[DllStackCheck(False)]` attribute for DLL Declares giving minor codegen size reduction on 32-bit API calls. +* `[Debuggable(False)]` attribute turns of breakpoints and stepping for the method or module. +* `[PopulateFrom()]` to populate enums via JSON +* `[Flags]` - Calculate implicit enum values as a flag set (powers of 2). (Note: To prevent confusion, once an explicit value is used, all remaining values after it must also be explicit)\ +![image](Images/4c4d2582-5c79-43bc-bd77-26cdfa49ed7f.png) + + + + +Note that you can also use VBx attributes with the new syntax; `[PredeclaredId]`, `[Hidden]`, `[Restricted]` \etc. + +# Standard Library Enhancements + +## Unicode support +Native functions that take string arguments, such as `MsgBox` and FileSystem functions (e.g. `Open`, `Dir`, `Mkdir`, `Kill`, and `RmDir`) now support Unicode. Additionally, .twin files make this easy to use as the editor supports Unicode as well. So you can paste a Unicode string in the editor, see it appear correctly, then have the same string correctly displayed by tB functions and controls. + +### Encoding options for file i/o + +The `Open` statement supports Unicode through the use of a new `Encoding` keyword and variable, and allows you to specify a wide range of encoding options in addition to standard Unicode options. + +Usage example: + +``` vb +Open "C:\MyFile.txt" For Input Encoding utf-8 As #1 +``` + +The full list of encoding options currently defined (and don't worry, these will come up in Intellisense) is: `default_system_ansi`, `utf_7`, `utf_7_bom`, `utf_8`, `utf_8_bom`, `utf_16`, `utf_16_bom`, `us_ascii`, `koi8_u`, `koi8_r`, `big5`, `iso_8859_1_latin1`, `iso_8859_2_latin2`, `iso_8859_3_latin3`, `iso_8859_4_latin4`, `iso_8859_5_cyrillic`, `iso_8859_6_arabic`, `iso_8859_7_greek`, `iso_8859_8_hebrew`, `iso_8859_9_latin5_turkish`, `iso_8859_10_latin6_nordic`, `iso_8859_11_thai`, `iso_8859_13_latin8_baltic`, `iso_8859_14_latin8_celtic`, `iso_8859_15_latin9_euro`, `iso_8859_16_latin10_balkan`, `windows_1250_central_europe`, `windows_1251_cyrillic`, `windows_1252_western`, `windows_1253_greek`, `windows_1254_turkish`, `windows_1255_hebrew`, `windows_1256_arabic`, `windows_1257_baltic`, `windows_1258_vietnamese`, `ibm_850_western_europe`, `ibm_852_central_and_eastern_europe`, `ibm_855_cyrillic`, `ibm_856_hebrew`, `ibm_857_turkish`, `ibm_858_western_europe`, `ibm_860_portuguese`, `ibm_861_icelandic`, `ibm_862_hebrew`, `ibm_863_canadian`, `ibm_865_danish`, `ibm_866_cyrillic`, `ibm_869_greek`, `ibm_932_japanese`, and `ibm_949_korean`. + +Others with a similar format should be accepted depending on system support. + +## New Built-in functions: + +In addition to the new datatype-related and component name functions already described, the standard builtin `VBA` library now includes: + +* `IsArrayInitialized(variable)` - Determines if an array is initialized. Note: A `Variant` declared as empty array with `Array()` will return `True`. +* `RGBA(r, g, b, a)` - Like the `RBG()` function, only including the alpha channel. +* `RBG_R(rgba)`, `RGB_B(rgba)`, `RBG_G(rgba)`, and `RGBA_A(rgba)` - Get the values for individual channels. +* `TranslateColor(ColorValue, Optional Palette)` - Translates an OLE color value to an RGB color. +* `ProcessorArchitecture()` - Returns either `vbArchWin32` or `vbArchWin64`, depending on application bitness. +* `CallByDispId(Object, DispId, CallType, Arguments)` - Similar to `CallByName()`, but uses the dispatch id instead of method name. +* `RaiseEventByName(Object, Name, Args)` - Invokes an event on class, using arguments specified as a single `Variant` containing an array. +* `RaiseEventByName2(Object, Name, Arg1, Arg2, ...)` - Invokes an event on class, using arguments specified as a ParamArray. +* `PictureToByteArray(StdPicture)` - Converts a picture to a byte array; Globals.LoadPicture supports loading from byte arrays. +* `CreateGUID()` - Returns a string with a freshly generated GUID. +* `AllocMem(size)` and `FreeMem` - allocate and free memory from the process heap. +* `Int3Breakpoint` - Inserts a true breakpoint helpful for attached external debuggers. +* `GetDeclaredTypeProgId(Of T)` / `GetDeclaredTypeClsid(Of T)` generics for getting strings of ProgID/CLSID. +* `GetDeclaredMinEnumValue(Of T)` / `GetDeclaredMaxEnumValue(Of T)` generics +* Some `Interlocked*` functions + +### Built in runtime functions and redirects from msvbvm60.dll + +tB has built in support for some of the most commonly used runtime functions, for compatibility. These all support both 32 and 64bit. Unless otherwise noted, all of these function in two ways: First, built in native versions that are always present (unless you remove the basic compiler packages), with the most common arrangements of arguments. These don't require a `Declare` statement. If you *do* provide a `Declare` version, tB will allow whatever arrangements of arguments you specify (e.g. `As Any` instead of `As LongPtr`), mapped to an alias if provided. + +* Memory functions: `GetMem1`, `GetMem2`, `GetMem4`, `GetMem8`, `PutMem1`, `PutMem2`, `PutMem4`, `PutMem8` with new additions `GetMemPtr` and `PutMemPtr` pegged to the current pointer size. +* `vbaObjSet`, `vbaObjSetAddref`, `vbaCastObj`, and `vbaObjAddref` for manipulating object assignments through pointers. +* `vbaCopyBytes` and `vbaCopyBytesZero` +* `vbaAryMove` and `vbaRefVarAry` (currently only with a `Declare` statement). +* tB also has an instrinsic `VarPtr` but will still redirect calls via a declare statement, e.g. aliases used for arrays (though tB's `VarPtr` supports arrays natively). + +### New `App` object properties + +* `App.IsInIDE` - `True` when running from the IDE. +* `App.IsElevated` - Returns whether the program is currently running with administrator rights. +* `App.LastBuildPath` - Returns the full path of the last build. Does not persist between compiler/IDE restarts. +* `App.Build` - For the additional version number field. +* `App.ModulePath` - Returns the full path of the currently executing module. For example, if placed in a DLL and called from an EXE, the path of the DLL would be returned. Also, the twinBASIC debugger DLL is given when running from the IDE, when the method is in the app itself. + +# GUI components + +## Support for modern image formats +You no longer face an incredibly limited format selection for images in tB Forms and Controls; not only do the Bitmap and Icon formats support the full range of formats for those, you can additionally load PNG Images, JPEG Images, Metafiles (.emf/.wmf), and SVG Vector Graphics (.svg). + +### Improved `LoadPicture` +Additionally, `LoadPicture` can load all image types directly from a byte array, rather than requiring a file on disk. You can use this to load images from resource files or other sources. Note that if your projects references stdole2.tlb (most do), currently you must qualify it as `Global.LoadPicture` to get tB's custom binding that supports byte arrays. + +### High quality scaling in Image controls +Image controls now offer a `StretchMode` property that allows you to choose Bilinear, Bicubic, Lanczos3 and Lanczos8 strectching algorithms, which are far superior to the default stretching algorithm. These use built in algorithms so do not add additional depencies or API calls. + +## Transparency and Alpha Blending on Forms + +## Form.TransparencyKey +This new property specifies a color that will be transparent to the window below it in the z-order (all windows, not just in your project). Setting this property will cause the specified color to be 100% transparent. A Shape control with a solid `FillStyle` is a helpful tool to color the areas of the form in the key color. + +## Form.Opacity + +This sets an alpha blending level for the entire form. Like transparency, this is to all windows immediately underneath it. Note that any areas covered by the `TransparencyKey` color will remain 100% transparent. + +The following image shows a Form with a `TransparencyKey` of Red, using a Shape control to define the transparent area, while also specifying 75% `Opacity` for the entire form: + +![image alt ><](Images/85f25aa2-abc8-4d42-8510-078f8ee4a324.png) + +## Additional Form features + +In addition to the above, forms have: + +* `DpiScaleX`/`DpiScaleY` properties to retrieve the current values +* `.MinWidth`, `.MinHeight`, `.MaxWidth`, and `.MaxHeight` properties so subclassing isn't needed for this +* `Form.TopMost` property. +* Control anchoring: control x/y/cx/cy can made relative, so they're automatically moved/resized with the Form. For example if you put a TextBox in the bottom right, then check the Right and Bottom anchors (in addition to Top and Left), the bottom right will size with the form on resize. This saves a lot of boiler-plate sizing code. +* Control docking: Controls can be fixed along one of the sides of the Form (or container), or made to fill the whole Form/container. Multiple controls can be combined and mixed/matched in docking positions. + +For more information on Control Anchoring and Control Docking, see the Wiki entry [Control Anchoring and Docking ‐ Automatic size and position management](../Anchoring-Docking). + +## Unicode support +All tB-implemented controls support Unicode, both in the code editor and when displayed. + +**Important:** If you subclass controls, note that this means you will receive the Unicode (W) version of window messages, e.g. ListViews will send `LVN_GETDISPINFOW (LVN_FIRST - 77)` instead of `LVN_GETDISPINFOA (LVN_FIRST - 50)`. + +## UserControl Enhancements + +The UserControl object now provides the new Boolean property `PreKeyEvents` that enables corresponding new events `PreKeyDown` and `PreKeyUp`. These allow handling special keys like tab, arrows, etc without OS or COM hooks (for example, based on the `IOleInPlaceActiveObject` interface). These work with all child windows inside the UserControl, including ones created by `CreateWindowEx`. You can also access raw message data in the `PreKeyDown`/`PreKeyUp` event handlers with the new `PreKeyWParam`/`PreKeyLParam` and `PreKeyTargetHwnd` UserControl properties. + + +## Control Modernization + +tB will eventually replace all built in controls that you're used to, for now the ones available are: CommandButton, TextBox, ComboBox, CheckBox, OptionButton, Label, Frame, PictureBox, Line, Shape, VScrollBar, HScrollBar, Timer, DriveListBox, DirListBox, FileListBox, Image, and Data from the basic set; then, ListView, TreeView, ProgressBar, DTPicker, MonthView, Slider, and UpDown from the Common Controls. + +* Controls support x64: Every control can be compiled both as 32bit and 64bit without changing anything.\ +* Controls are DPI aware: They will automatically size correctly when dpi awareness is enabled for your app.\ +* Controls support Visual Styles per-control: Comctl6 styles can be applied, or not, on a control-by-control basis with the `.VisualStyles` property. + +### Alternatives for unimplemented controls + +The best option is Krool's VBCCR and VBFlexGrid projects. These are now available [from the Package Server](Packages---Importing-a-package-from-TWINSERV) in x64-compatible form, and are also DPI aware and support Visual Styles. + +Additionally, the original OCX controls provided by Microsoft will work fine; however, they're mostly 32-bit only. The x64 version of `MSComCtl.ocx` doesn't come with Windows and isn't legally redistributable but if you have Office 64bit, it works in tB. + +## Misc additional control properties and enhancements + +* `TextBox.NumbersOnly` property: Restricts input to 0-9 by setting the `ES_NUMBER` style on the underlying control. + +* `TextBox.TextHint` property: Sets the light gray hint text in an empty TextBox (`EM_SETCUEBANNER`). + +* `PictureDpiScaling` property for forms, usercontrols and pictureboxes: PictureDpiScaling property allows you to turn off DPI scaling of images so that they display at 1:1 rather than allowing the OS to stretch them. The idea being you may want to choose a different bitmap manually, rather than apply the somewhat limited OS-stretching. + +* `Label.VerticalAlignment` property: Defaults to Top. + +* `Label.LineSpacing` property (in twips, default is 0) + +* `Label.Angle` property (in degrees, rotates the label text) + +* `Label.BorderCustom` property (has suboptions to set size, padding and color of borders independently for each side). + +* `Timer.Interval` can now be set to any positive `Long` instead of being limited to 65,535. + +* `StrConv()` now has `vbUTF8` / `vbFromUTF8` + +## New Controls + +### QR Code Control +![image](Images/54ed49d8-b434-45e3-9e63-a1fe75cdf814.png) + +Easily display custom QR codes with a native control. + +### Multiframe Control +![image-15](Images/4ad9c774-b31d-47d3-9963-6d99ac4f37bb.png) + +This control allows you to create a number of frames within it with their size specified as a percentage, such that as the control is resized the frames within expand proportionally. For details and a video demonstration, Mike Wolfe's twinBASIC Weekly Update [covered it when released](https://nolongerset.com/twinbasic-update-april-29-2025/#experimental-multi-frame-control).\ +Combined with anchors and docking, this allows designing highly functional and complex layouts visually, without writing any code to handling resizing. + +### CheckMark Control +![image](Images/5fc60b7b-4f54-445c-8504-451019b7ec55.png) + +Primarily intended for reports but available in Forms and UserControls as well, the CheckMark control provides a scalable check component where this is fixed to a single size in a normal CheckBox control. + +# Design Experience and Compiler Features + +## Customize COM initialization +You can specify the call used by the hidden entry point with the following options: `CoInitialize STA`, `CoInitializeEx MTA`, `OleInitialize STA`. If you don't know the difference, don't change it from the default. + +## Customize symbol table parameters + +You can adjust the following parameters: Max Size Raw, Max Size Lookup, and Data Type Lookup. These options allow for compiling very large projects that would otherwise have issues, and the compiler will notify you if these values need to be increased. + +## Sanitize Boolean types +Under the hood, a Boolean is a 2-byte type. With memory APIs, or when receiving these from outside code, it's possible to store values other than the ones representing `True` and `False`. This option validates Booleans from external sources, e.g. COM objects and APIs, to ensure only the two supported values are stored. + +## Stale/dangling pointer detection + +Bugs result from using Strings and Variants after they have been freed. It may not be noticed immediately if the memory has not been overwritten, but it's sometimes hard to detect and can cause issues like a String displaying it's previous value or garbage. This debugging option detects use-after-free, and replaces the data with a special symbol indicating the problem. Below shows an example where the ListView ColumnHeader text had been set by previously-freed string and detected by this feature: + +![image](Images/021f6cbf-acce-445d-ade7-3fcad0af4927.png) + +Previously, it had shown the same text for every column-- but only under certain circumstances, leading to the issue being overlooking for a long time. + +## Additional compiler options + +- Projects can be marked `LARGEADDRESSAWARE`. + +- A manual base address can be specified + +- Option to strip PE relocation symbols + +### Exploit mitigation + +You can enable the following: + +Data execution prevention (DEP) + +Address-space layout randomization (ASLR) + +## Debug Trace Logger +New to the debugging experience is a powerful trace logging feature that can automatically create detailed logs to either the debug console or a file. Messages can be output to the new system with `Debug.TracePrint`. The logger works both when running from the IDE and in compiled executables. + +![image](Images/4fc2bf99-2bec-4943-837d-21038d791574.png) + +## Compiler Warnings + +twinBASIC provides compiler warnings during design time for common bad practices or likely oversights, including: +* Warnings for likely-incorrect hex literals\ +Non-explicit values are coerced into the lowest possible type first. So if you declare a constant as `&H8000`, the compiler sees it as an -32,768 `Integer`, and when you're putting that into a `Long` you almost certainly do not want -32,768, you want **positive** 32,768, which requires you to instead use `&H8000&`.\ +This warning is supplied for `&H8000`-`&HFFFF` and `&H80000000`-`&HFFFFFFFF`. + +* Warnings for implicit variable creation with `ReDim`.\ +When you use `ReDim myArray(1)`, the `myArray` variable is created for you, when it's good practice to declare all variables first. + +* Warnings for use of `DefType`\ +This feature is discouraged for it making code difficult to read and prone to difficult to debug errors. + +The full list can be found in your project's Settings page:\ +![image](Images/017bd6f8-4b35-43a9-b6be-84cba69daf64.png) + +### Adjusting warnings +Each warning has the ability to set them to ignore or turn them into an error both project-wide via the Settings page, and per-module/class, and per-procedure with `[IgnoreWarnings(TB___)]`, `[EnforceWarnings(TB____)]`, and `[EnforceErrors(TB____)]` attributes, where the underscores are replaced with the **full** number, e.g. `[IgnoreWarnings(TB0001)]`; the leading zeroes must be included. + +### Strict mode + +twinBASIC has added the following warning messages to support something similar to .NET's Strict Mode, where certain implicit conversions are not allowed and must be made explicit. By default, these are all set to be ignored, and must be enabled in the "Compiler Warnings" section of Project Settings or per-module/procedure with `[EnforceWarnings()]`. All of these can be configured individually and ignored for procedure/module scope with `[IgnoreWarnings()]` + +**TB0018: Impicit narrowing conversion**\ +Such as converting a Long to Integer; if you have `Dim i As Integer, l As Long` then `i = l` will trigger the warning, and `i = CInt(l)` would be required to avoid it. + +**TB0019: Implicit enumeration conversion**\ +When assigning a member of one Enum to a variabled typed as another, such as `Dim day As VbDayOfWeek: day = vbBlack`. The `CType(Of )` operator whose use in pointers was described in the previous section is also used to specify an explicit type conversion in this case; the warning would not be triggered by `day = CType(Of VbDayOfWeek)(vbBlack)`. + +**TB0020: Suspicious interface conversion**\ +If a declared coclass doesn't explicitly name an interface as supported, converting to it will trigger this warning, e.g. + +``` vb +Dim myPic As StdPicture +Dim myFont As StdFont +Set myFont = myPic +``` + +You'd use `Set myFont = CType(OfStdFont)(myPic)` to avoid this warning. + +**TB0021: Implicit enumeration conversion to/from numeric** +Triggered by assigning a numeric literal to a variabled typed as an Enum, such as `Dim day As VbDayOfWeek: day = 1`. To avoid it you'd use `day = CType(Of VbDayOfWeek)(1)`. + +## Run some Subs from the IDE + +The CodeLens feature allows running Subs and Functions, with no arguments and in modules (but not classes/Forms/UserControls) right from the editor without starting the full program. It has robust access to your code; it can access constants, call other functions both instrinsic and user-define, call APIs, and print to the Debug Console.\ +Methods eligible to run with CodeLens (when enabled), have a bar above them that you can click to run:\ +![image](Images/351d0147-cad3-4e16-89e5-0a9e43496740.png) + + +## Modern IDE features + +While the twinBASIC IDE still has a lot of work planned, it already includes a number of features that make life much easier found in other modern IDE, but not the ancient VBx IDEs, including: + +* Fully theme-able, with Dark (default), Light, and Classic (Light) built in, and an easy inheritance-based system to add your own themes via CSS files. + +* Code folding, with foldable custom-defined regions via `#Region "name" ... #End Region` blocks. + +* Fully customizable keyboard shortcuts covering all commands, with ability to save and switch between different sets. + +* Sticky-scroll, which keeps context lines at the top showing major sections of code like module, region, method, `With` blocks, etc. + +* Indent guides, lines drawn along common indent points to help line things up right. + +* Auto-indent on paste. + +* Paste as comment. + +* Full Unicode support in .twin files, so you can use the full Unicode range of the font in your comments and strings. + +* Inline code hints, which provide annotations at the end of blocks for what the block is (see picture). + +* Code mini-map, shows a graphics overview of the code structure alongside the scroll bar, helping to guide your scrolling. + +* Advanced Information popup, which shows offsets for UDT members, their total size via both `Len()` plus `LenB()`, and their alignment; and v-table entry offsets for interfaces and classes, as well as their inheritance chain. + +* A type library viewer for controls and TLB files that displays the full contents in twinBASIC-style syntax rather than ODL. + +* Color-matching for parentheses and brackets. + +* A History panel containing a list of recently modified methods. + +* An Outline panel with selectable categories. + +* Problems panel, provides a list of all current errors and warnings (you can filter to show only one or the other). + +* On the Form Designer, control with `Visible = False` are faded to visually indicate this. Also, pressing and holding Control shows the tab index of each tab stop. + +![image](Images/014a1d28-30af-4a4d-8b9b-83ab6084f00a.png)\ +[Full size](Images/fafaloneIDEscreenshot1.png) + +* New code structure based Project Explorer:\ +![image](Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png) + +The classic file-based view is still used by default, you can activate the new view with a toggle button:\ +![image](Images/b000d3aa-3689-4d94-88e3-bca44f8b7de6.png) + + +## Package Server + +Code can be grouped as a package, and published to an online server. You can have Private packages, visible only to you, or Public packages, visible to everyone. + +![image](Images/5951dab6-738e-4b63-83c4-3331ec6d36b9.png) + +For more information, see the following pages: + +[What is a package](/Packages/What-Is) + +[Creating a TWINPACK package](/Packages/Creating-TWINPACK) + +[Importing a package from a TWINPACK file](/Packages/Importing-TWINPACK) + +[Importing a package from TWINSERV](/Packages/Importing-TWINSERV) + +[Updating a package](/Packages/Updating) + +## View Forms and Packages as JSON +Project forms and packages are stored as JSON format data, and you can view this by right-click in Project Explorer and selecting 'View as JSON'. This is particularly interesting for packages as it exposes the entire code in a much more easily parsed format. + +![image](Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png) + +![image](Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png) + + +--- + +# Many more to come! + +This list has covered all new features at the present time. There's many more planned, including built-in multithreading syntax, unsigned variable types, native support for aliases (currently supported in type libraries only), full inheritance, and more! If there's a feature you'd like to see, please feel welcome to make a feature request by [posting an issue in the main twinBASIC GitHub repository](https://github.com/twinbasic/twinbasic/issues). \ No newline at end of file diff --git a/docs/Features/Windowless vs windowed controls.md b/docs/Features/Windowless vs windowed controls.md new file mode 100644 index 00000000..08885957 --- /dev/null +++ b/docs/Features/Windowless vs windowed controls.md @@ -0,0 +1,147 @@ +--- +title: Windowless Controls vs. Windowed Controls +parent: Features +nav_order: 3 +permalink: /Features/Windowless/ +--- + +# Windowless Controls vs. Normal (Windowed) Controls + +| Feature | **Windowless Controls** | **Normal Controls** | +| --- | --- | --- | +| **Window Handle (hWnd)** | No hWnd; drawn directly on container's Device Context (DC) | Each has its own hWnd | +| **Performance** | Lower overhead, faster rendering3 | Higher overhead due to window management | +| **Transparency & Shape** | Supports transparent backgrounds and non-rectangular regions | Limited to rectangular, opaque regions | +| **Z-Order Behavior** | Always rendered beneath windowed controls4 | Can float above other controls | +| **Input Handling** | Requires manual routing of input (keyboard, mouse) via container | OS handles input natively | +| **Accessibility** | Needs explicit support via interfaces like `IAccessibleWindowlessSite`1 | Built-in accessibility support | +| **Known Issues** | May require custom handling to work around known issues in twinBASIC (e.g., events not firing)2 | More complete and stable | +| **Use Case Fit** | Ideal for lightweight, static UI elements (e.g., labels, images) | Best for interactive or focusable controls (e.g., textboxes, buttons) | + +--- + +### ✅ **Benefits of Windowless Controls** + +- **Performance Boost**: No hWnd means less GDI overhead—great for forms with many static elements.3 +- **Visual Flexibility**: Enables transparent or shaped UI elements (e.g., rounded buttons, overlays). +- **Resource Efficiency**: Helps avoid hitting system handle limits in control-heavy UIs. + +--- + +### ⚠️ **Drawbacks** + +- **Complex Input Handling**: You must manually forward focus, mouse, and keyboard events from the container. +- **Z-Order Limitations**: Cannot appear above windowed controls—problematic for overlays or tooltips.4 +- **Quirks**: twinBASIC has some known issues with windowless control events and other features.2 +- **Accessibility Overhead**: Requires extra work to expose accessibility interfaces.1 + +--- + +1 [IAccessibleWindowlessSite Interface on Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/oleacc/nn-oleacc-iaccessiblewindowlesssite) + +2 Originally reported in [twinBASIC GitHub Issue #1310 – Windowless Anchor Resizing Bug](https://github.com/twinbasic/twinbasic/issues/1310). Fixed in BETA 162. + +3 Overview of [GDI object handles](https://learn.microsoft.com/en-us/windows/win32/sysinfo/gdi-objects) and [hWnd user object handles](https://learn.microsoft.com/en-us/windows/win32/sysinfo/user-objects) in Windows UI architecture: [MSDN – Window Resources](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-resources) + +4 Background on Z-order rendering and Windows control layering: [Windows Controls - Z-order](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#z-order) + +--- + +## Use Case Examples + +### When to Choose Windowless Controls + +- **Static UI Elements**: Ideal for labels, decorative images, or non-interactive overlays where performance and visual flexibility are key. +- **Transparent or Shaped Elements**: Perfect for rounded buttons, custom-shaped overlays, or transparent backgrounds. +- **Control-Heavy Forms**: Useful in scenarios where system handle limits might be exceeded, such as dashboards with hundreds of static elements. + +### When to Choose Normal (Windowed) Controls + +- **Interactive Elements**: Best for textboxes, buttons, dropdowns, or any control requiring user input or focus. +- **Layered UI Components**: Necessary for tooltips, modal dialogs, or any element that needs to float above other controls. +- **Accessibility Requirements**: Recommended for applications where built-in accessibility support is critical. + +### Hybrid Layouts + +- **Combining Both Types**: Use windowless controls for static elements and normal controls for interactive ones to balance performance and functionality. +- **Example Scenario**: A dashboard with static labels and graphs (windowless) alongside interactive filters and buttons (windowed). + +--- + +## Real-World Examples + +### 🪟 Windowless Control Examples + +- **[SweetIceLolly/VB6-MemoryDC](https://github.com/SweetIceLolly/VB6-MemoryDC)** – A VB6 project demonstrating off-screen rendering using memory device contexts. Great for illustrating custom-drawn, windowless UI elements. +- **[fafalone/WinDevLib](https://github.com/fafalone/WinDevLib)** – A twinBASIC library with low-level Win32 API wrappers. Includes examples of custom rendering and control logic that bypass hWnds. +- **[fafalone/EventTrace](https://github.com/fafalone/EventTrace)** – A twinBASIC port of an ETW file activity monitor. Uses lightweight, non-windowed UI elements for performance. + +### 🧱 Windowed Control Examples + +- **[fafalone/UIRibbonDemos](https://github.com/fafalone/UIRibbonDemos)** – twinBASIC demos of the Windows Ribbon UI framework. Showcases interactive, hWnd-backed controls with full accessibility and Z-order behavior. +- **[SweetIceLolly/DragControlsIDE](https://github.com/SweetIceLolly/DragControlsIDE)** – A VB6-based IDE-like interface with draggable, windowed controls. Useful for demonstrating layout and anchoring behavior. +- **[SweetIceLolly/DragControlsIDE-v2](https://github.com/SweetIceLolly/DragControlsIDE-v2)** - an updated version of the above. +- **[bclothier/TwinBasicSevenZip](https://github.com/bclothier/TwinBasicSevenZip)** – A twinBASIC wrapper for 7-Zip COM integration. Includes a UI with standard windowed controls for file selection and progress. + +--- + +### 🖨️ Printing Mixed-Control Forms in VBx/twinBASIC + +#### ✅ What Works Out of the Box + +* **Windowed controls** (e.g., `TextBox`, `CommandButton`) can often be captured using `Form.DrawToDC` or `PrintForm` in VB6, or by rendering the form’s `hDC` in twinBASIC. +* **Windowless controls**, however, don’t have their own `hWnd` or device context, so they won’t appear unless you explicitly draw them. + +--- + +#### 🧰 Recommended Strategy + +1. **Render the Entire Form to a Bitmap** + + * In VB6: Use `BitBlt` or `PaintPicture` to copy the form’s visible area. + * In TwinBASIC: Use the form’s `Canvas` or `ICustomControl.Paint` logic to manually render windowless elements to a bitmap. + +2. **Ensure Windowless Controls Are Painted** + + * For custom controls using `ICustomControl.Paint`, call their paint routines manually into the same bitmap or `DC`. + * If using `Canvas.AddElement`, simulate a paint pass with the same layout logic used during runtime. + +3. **Send the Bitmap to the Printer** + + * Use `Printer.PaintPicture` in VB6 or `Printer.Canvas.DrawImage` in twinBASIC (if available). + * Alternatively, use `GDI` or `GDI+` APIs to send the bitmap to the printer’s `DC`. + +--- + +#### 🧪 Tips for Accuracy + +* **Z-Order Matters**: Since windowless controls render behind windowed ones, draw them first. +* **DPI Awareness**: Match the printer’s DPI to your form’s layout scale to avoid blurry output. +* **Off-Screen Rendering**: Consider rendering to a memory `DC` or `StdPicture` object before printing to avoid flicker or partial paints. + +--- + +#### Code Snippet for twinBASIC + +``` vb +' Example: Printing a Mixed-Control Form in twinBASIC +Dim bmp As StdPicture +Set bmp = CreateCompatibleBitmap(Me.Width, Me.Height) + +' Render windowless controls +For Each ctrl In Me.Controls + If TypeOf ctrl Is ICustomControl Then + ctrl.Paint bmp.Canvas + End If +Next + +' Render windowed controls +Me.DrawToDC bmp.Canvas + +' Send to printer +Printer.Canvas.DrawImage bmp, 0, 0 +Printer.EndDoc +``` +--- + +For DPI-aware, multi-monitor layout work, windowless controls can be a powerful tool—especially for static or decorative elements—but they demand more orchestration when interactivity or layering is involved. If you're building a hybrid layout, a mix of both types might give you the best of both worlds. diff --git a/docs/Features/index.md b/docs/Features/index.md new file mode 100644 index 00000000..2efc4495 --- /dev/null +++ b/docs/Features/index.md @@ -0,0 +1,7 @@ +--- +title: Features +nav_order: 6 +permalink: /Features/ +--- + +# Features \ No newline at end of file diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 00000000..ad88c009 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve + +group :jekyll_plugins do + gem "github-pages", ">= 232" + gem "jekyll-feed", "~> 0.12" + gem "jekyll-remote-theme", "= 0.4.3" +end + +platforms :windows, :jruby do + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" +end + +gem "wdm", "~> 0.1", :platforms => [:windows] + +# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem +# do not have a Java counterpart. +gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 00000000..daf48533 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,392 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (8.1.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.8) + public_suffix (>= 2.0.2, < 8.0) + base64 (0.3.0) + bigdecimal (4.0.1) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + colorator (1.1.0) + commonmarker (0.23.12) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + csv (3.3.5) + dnsruby (1.73.1) + base64 (>= 0.2) + logger (~> 1.6) + simpleidn (~> 0.2.1) + drb (2.2.3) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + ethon (0.15.0) + ffi (>= 1.15.0) + eventmachine (1.2.7) + execjs (2.10.0) + faraday (2.14.0) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-net_http (3.4.2) + net-http (~> 0.5) + ffi (1.17.2-x64-mingw-ucrt) + forwardable-extended (2.6.0) + gemoji (4.1.0) + github-pages (232) + github-pages-health-check (= 1.18.2) + jekyll (= 3.10.0) + jekyll-avatar (= 0.8.0) + jekyll-coffeescript (= 1.2.2) + jekyll-commonmark-ghpages (= 0.5.1) + jekyll-default-layout (= 0.1.5) + jekyll-feed (= 0.17.0) + jekyll-gist (= 1.5.0) + jekyll-github-metadata (= 2.16.1) + jekyll-include-cache (= 0.2.1) + jekyll-mentions (= 1.6.0) + jekyll-optional-front-matter (= 0.3.2) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.3.0) + jekyll-redirect-from (= 0.16.0) + jekyll-relative-links (= 0.6.1) + jekyll-remote-theme (= 0.4.3) + jekyll-sass-converter (= 1.5.2) + jekyll-seo-tag (= 2.8.0) + jekyll-sitemap (= 1.4.0) + jekyll-swiss (= 1.0.0) + jekyll-theme-architect (= 0.2.0) + jekyll-theme-cayman (= 0.2.0) + jekyll-theme-dinky (= 0.2.0) + jekyll-theme-hacker (= 0.2.0) + jekyll-theme-leap-day (= 0.2.0) + jekyll-theme-merlot (= 0.2.0) + jekyll-theme-midnight (= 0.2.0) + jekyll-theme-minimal (= 0.2.0) + jekyll-theme-modernist (= 0.2.0) + jekyll-theme-primer (= 0.6.0) + jekyll-theme-slate (= 0.2.0) + jekyll-theme-tactile (= 0.2.0) + jekyll-theme-time-machine (= 0.2.0) + jekyll-titles-from-headings (= 0.5.3) + jemoji (= 0.13.0) + kramdown (= 2.4.0) + kramdown-parser-gfm (= 1.1.0) + liquid (= 4.0.4) + mercenary (~> 0.3) + minima (= 2.5.1) + nokogiri (>= 1.16.2, < 2.0) + rouge (= 3.30.0) + terminal-table (~> 1.4) + webrick (~> 1.8) + github-pages-health-check (1.18.2) + addressable (~> 2.3) + dnsruby (~> 1.60) + octokit (>= 4, < 8) + public_suffix (>= 3.0, < 6.0) + typhoeus (~> 1.3) + html-pipeline (2.14.3) + activesupport (>= 2) + nokogiri (>= 1.4) + http_parser.rb (0.8.0) + i18n (1.14.8) + concurrent-ruby (~> 1.0) + jekyll (3.10.0) + addressable (~> 2.4) + colorator (~> 1.0) + csv (~> 3.0) + em-websocket (~> 0.5) + i18n (>= 0.7, < 2) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (>= 1.17, < 3) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + webrick (>= 1.0) + jekyll-avatar (0.8.0) + jekyll (>= 3.0, < 5.0) + jekyll-coffeescript (1.2.2) + coffee-script (~> 2.2) + coffee-script-source (~> 1.12) + jekyll-commonmark (1.4.0) + commonmarker (~> 0.22) + jekyll-commonmark-ghpages (0.5.1) + commonmarker (>= 0.23.7, < 1.1.0) + jekyll (>= 3.9, < 4.0) + jekyll-commonmark (~> 1.4.0) + rouge (>= 2.0, < 5.0) + jekyll-default-layout (0.1.5) + jekyll (>= 3.0, < 5.0) + jekyll-feed (0.17.0) + jekyll (>= 3.7, < 5.0) + jekyll-gist (1.5.0) + octokit (~> 4.2) + jekyll-github-metadata (2.16.1) + jekyll (>= 3.4, < 5.0) + octokit (>= 4, < 7, != 4.4.0) + jekyll-include-cache (0.2.1) + jekyll (>= 3.7, < 5.0) + jekyll-mentions (1.6.0) + html-pipeline (~> 2.3) + jekyll (>= 3.7, < 5.0) + jekyll-optional-front-matter (0.3.2) + jekyll (>= 3.0, < 5.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.3.0) + jekyll (>= 3.0, < 5.0) + jekyll-redirect-from (0.16.0) + jekyll (>= 3.3, < 5.0) + jekyll-relative-links (0.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-remote-theme (0.4.3) + addressable (~> 2.0) + jekyll (>= 3.5, < 5.0) + jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) + rubyzip (>= 1.3.0, < 3.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.8.0) + jekyll (>= 3.8, < 5.0) + jekyll-sitemap (1.4.0) + jekyll (>= 3.7, < 5.0) + jekyll-swiss (1.0.0) + jekyll-theme-architect (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-cayman (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-dinky (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-hacker (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-leap-day (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-merlot (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-midnight (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-minimal (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-modernist (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-primer (0.6.0) + jekyll (> 3.5, < 5.0) + jekyll-github-metadata (~> 2.9) + jekyll-seo-tag (~> 2.0) + jekyll-theme-slate (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-tactile (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-time-machine (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-titles-from-headings (0.5.3) + jekyll (>= 3.3, < 5.0) + jekyll-watch (2.2.1) + listen (~> 3.0) + jemoji (0.13.0) + gemoji (>= 3, < 5) + html-pipeline (~> 2.2) + jekyll (>= 3.0, < 5.0) + json (2.18.0) + kramdown (2.4.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + liquid (4.0.4) + listen (3.9.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + mercenary (0.3.6) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + minitest (6.0.0) + prism (~> 1.5) + net-http (0.9.1) + uri (>= 0.11.1) + nokogiri (1.18.10-x64-mingw-ucrt) + racc (~> 1.4) + octokit (4.25.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + prism (1.7.0) + public_suffix (5.1.1) + racc (1.8.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rexml (3.4.4) + rouge (3.30.0) + rubyzip (2.4.1) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sawyer (0.9.3) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + securerandom (0.4.1) + simpleidn (0.2.3) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + typhoeus (1.5.0) + ethon (>= 0.9.0, < 0.16.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + tzinfo-data (1.2025.3) + tzinfo (>= 1.0.0) + unicode-display_width (1.8.0) + uri (1.1.1) + wdm (0.2.0) + webrick (1.9.2) + +PLATFORMS + x64-mingw-ucrt + +DEPENDENCIES + github-pages + http_parser.rb (~> 0.6.0) + jekyll-feed (~> 0.12) + jekyll-remote-theme (= 0.4.3) + tzinfo (>= 1, < 3) + tzinfo-data + wdm (~> 0.1) + +CHECKSUMS + activesupport (8.1.1) sha256=5e92534e8d0c8b8b5e6b16789c69dbea65c1d7b752269f71a39422e9546cea67 + addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7 + coffee-script (2.4.1) sha256=82fe281e11b93c8117b98c5ea8063e71741870f1c4fbb27177d7d6333dd38765 + coffee-script-source (1.12.2) sha256=e12b16fd8927fbbf8b87cb2e9a85a6cf457c6881cc7ff8b1af15b31f70da07a4 + colorator (1.1.0) sha256=e2f85daf57af47d740db2a32191d1bdfb0f6503a0dfbc8327d0c9154d5ddfc38 + commonmarker (0.23.12) sha256=da2d2f89c7c7b51c42c6e69ace3ab5df39497683f86e83aca7087c671d523ccd + concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab + connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a + csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f + dnsruby (1.73.1) sha256=6cf327f5fe2768deadb5e3f3e899ff1ae110aefcef43fef32e1e55e71289e992 + drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 + em-websocket (0.5.3) sha256=f56a92bde4e6cb879256d58ee31f124181f68f8887bd14d53d5d9a292758c6a8 + ethon (0.15.0) sha256=0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d + eventmachine (1.2.7) sha256=994016e42aa041477ba9cff45cbe50de2047f25dd418eba003e84f0d16560972 + execjs (2.10.0) sha256=6bcb8be8f0052ff9d370b65d1c080f2406656e150452a0abdb185a133048450d + faraday (2.14.0) sha256=8699cfe5d97e55268f2596f9a9d5a43736808a943714e3d9a53e6110593941cd + faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c + ffi (1.17.2-x64-mingw-ucrt) sha256=15d2da54ee578657a333a6059ed16eaba1cbd794ceecd15944825b65c8381ac0 + forwardable-extended (2.6.0) sha256=1bec948c469bbddfadeb3bd90eb8c85f6e627a412a3e852acfd7eaedbac3ec97 + gemoji (4.1.0) sha256=734434020cbe964ea9d19086798797a47d23a170892de0ce55b74aa65d2ddc1a + github-pages (232) sha256=2b40493d7327627e4ce45c47f4a9d4394e5eaa151f9d29bb924ff424c3132287 + github-pages-health-check (1.18.2) sha256=df893d4f5a4161477e8525b993dbe1c1eb63fbb86fb07b6e80996fd37a18843d + html-pipeline (2.14.3) sha256=8a1d4d7128b2141913387cac0f8ba898bb6812557001acc0c2b46910f59413a0 + http_parser.rb (0.8.0) sha256=5a0932f1fa82ce08a8516a2685d5a86031c000560f89946913c555a0697544be + i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 + jekyll (3.10.0) sha256=c4213b761dc7dfe7d499eb742d0476a02d8503e440c2610e19774ee7f0db8d90 + jekyll-avatar (0.8.0) sha256=ea736277c2de54a21300122096700517972a722d5c68ca83f8723b4999abfd4b + jekyll-coffeescript (1.2.2) sha256=894e71c2071a834e76eb7e8044944440a0c81c2c7092532fed1503b13d331110 + jekyll-commonmark (1.4.0) sha256=1731e658fe09ce040271e6878f83ad45bbf8d17b10ad03bf343546cca30f4844 + jekyll-commonmark-ghpages (0.5.1) sha256=d56722f23393e45625e6e1bac6d3c64bb5f5cdf6ca547338160536d61c27a4a4 + jekyll-default-layout (0.1.5) sha256=c626be4e4a5deafca123539da2cd22ff873be350cafd4da134039efdf24320af + jekyll-feed (0.17.0) sha256=689aab16c877949bb9e7a5c436de6278318a51ecb974792232fd94d8b3acfcc3 + jekyll-gist (1.5.0) sha256=495b6483552a3e2975a2752964ea7acddd545bc6e13ce2be15a50cec8d4c9f0f + jekyll-github-metadata (2.16.1) sha256=4cf29988bdaf24774a7bc07fae71e54424ddfaa2895f742d8fa3036d0db65b4c + jekyll-include-cache (0.2.1) sha256=c7d4b9e551732a27442cb2ce853ba36a2f69c66603694b8c1184c99ab1a1a205 + jekyll-mentions (1.6.0) sha256=39e801024cb6f2319b3f78a29999d0068ef5f68bc5202b8757d5354fef311ed9 + jekyll-optional-front-matter (0.3.2) sha256=ecdc061d711472469fcf04da617653b553e914c038a17df3b6a5f6f92aeb761b + jekyll-paginate (1.1.0) sha256=880aadf4b02529a93541d508c5cbb744f014cbfc071d0263a31f25ec9066eb64 + jekyll-readme-index (0.3.0) sha256=d74cc4de46b2d350229be7409495149e656a31fb5a5fe3fe6135dbf7435e1e32 + jekyll-redirect-from (0.16.0) sha256=6635cae569ef9b0f90ffb71ec014ba977177fafb44d32a2b0526288d4d9be6db + jekyll-relative-links (0.6.1) sha256=d11301f57b39e94b6c04fff2a3b145fe2f6a27be631a403e2542fa2e1548dd6d + jekyll-remote-theme (0.4.3) sha256=d3fde726484fb3df04de9e347baf75aaa3d5bfea771a330412e0c52608e54b40 + jekyll-sass-converter (1.5.2) sha256=53773669e414dc3bb070113befacb808576025a28cfa4a4accc682e90a9c1101 + jekyll-seo-tag (2.8.0) sha256=3f2ed1916d56f14ebfa38e24acde9b7c946df70cb183af2cb5f0598f21ae6818 + jekyll-sitemap (1.4.0) sha256=0de08c5debc185ea5a8f980e1025c7cd3f8e0c35c8b6ef592f15c46235cf4218 + jekyll-swiss (1.0.0) sha256=c299a855dca881fe868f21545c5489be50ddfbc0d54a80e8dbeb5a2ddc4888a3 + jekyll-theme-architect (0.2.0) sha256=7275d3dcaa6b34fcf92f2fe5cee92d49d66706d3b523003b1e67e9c668ff0440 + jekyll-theme-cayman (0.2.0) sha256=3c5f14f9c72a8eb03ecc74f9a3e5ecbbc55f9381339978b42dec216921865f2a + jekyll-theme-dinky (0.2.0) sha256=720b257091f0de3aa9394b25fd97d1b2b12cfaf00e060aff170f60e218a32c7c + jekyll-theme-hacker (0.2.0) sha256=816bf9f992ded0b1e1e69d8dece2574e8480efb5e9f84a2e1ac83bd717b8f78a + jekyll-theme-leap-day (0.2.0) sha256=921ea8305ae0285a881c9aa9dbe2375ed6f404b4f90067458e596891ef5ac7d1 + jekyll-theme-merlot (0.2.0) sha256=cbf2b21b62423561ca5b62e406dbb08f085e3a45daa7b3b4b9b3f24d08ded545 + jekyll-theme-midnight (0.2.0) sha256=009ff367350e83ff6095d98837bb411adb07b59a76f59f1d4a33ef927bb391de + jekyll-theme-minimal (0.2.0) sha256=a225210c35573ad2c9e57b81f16f678ca6c314394ec692502ccc6189d7e52d82 + jekyll-theme-modernist (0.2.0) sha256=4be775bc5edd53864c5e40c000c34db0dfd82dac800cff50371ef11da66dfbcf + jekyll-theme-primer (0.6.0) sha256=ce27282798217eb0957ba01ab3bf12996476348b625736fa8448f7a1b8a307b3 + jekyll-theme-slate (0.2.0) sha256=5e40909de712bbbefbc7a29f17c55bffa326c222f0a13ee1656229a7d43c3439 + jekyll-theme-tactile (0.2.0) sha256=b7861b48aed5b2385d7a146b13f31cb6f37afe3107f4a6b93b1c932b2d242652 + jekyll-theme-time-machine (0.2.0) sha256=bc3490a7eccfc24ca671780c9d4f531500936a361690020b19defe6105d74fe2 + jekyll-titles-from-headings (0.5.3) sha256=77366754e361ea7b5d87881f5b1380835f5ce910c240a4d9ac2d7afe86d28481 + jekyll-watch (2.2.1) sha256=bc44ed43f5e0a552836245a54dbff3ea7421ecc2856707e8a1ee203a8387a7e1 + jemoji (0.13.0) sha256=5d4c3e8e2cbbb2b73997c31294f6f70c94e4d4fade039373e86835bcf5529e7c + json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505 + kramdown (2.4.0) sha256=b62e5bcbd6ea20c7a6730ebbb2a107237856e14f29cebf5b10c876cc1a2481c5 + kramdown-parser-gfm (1.1.0) sha256=fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729 + liquid (4.0.4) sha256=4fcfebb1a045e47918388dbb7a0925e7c3893e58d2bd6c3b3c73ec17a2d8fdb3 + listen (3.9.0) sha256=db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mercenary (0.3.6) sha256=2a084b18f5692c86a633e185d5311ba6d11fc46c802eb414ae05368178078a82 + minima (2.5.1) sha256=520e52bc631fb16cbb8100660f6caa44f97859e2fa7e397d508deb18739567be + minitest (6.0.0) sha256=4ca597fc1d735ea18d2b4b98c5fb1d5a6da4a6f35ddf32bd5fa3eded33a453be + net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996 + nokogiri (1.18.10-x64-mingw-ucrt) sha256=64f40d4a41af9f7f83a4e236ad0cf8cca621b97e31f727b1bebdae565a653104 + octokit (4.25.1) sha256=c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96 + pathutil (0.16.2) sha256=e43b74365631cab4f6d5e4228f812927efc9cb2c71e62976edcb252ee948d589 + prism (1.7.0) sha256=10062f734bf7985c8424c44fac382ac04a58124ea3d220ec3ba9fe4f2da65103 + public_suffix (5.1.1) sha256=250ec74630d735194c797491c85e3c6a141d7b5d9bd0b66a3fa6268cf67066ed + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe + rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (3.30.0) sha256=a3d353222aa72e49e2c86726c0bcfd719f82592f57d494474655f48e669eceb6 + rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615 + safe_yaml (1.0.5) sha256=a6ac2d64b7eb027bdeeca1851fe7e7af0d668e133e8a88066a0c6f7087d9f848 + sass (3.7.4) sha256=808b0d39053aa69068df939e24671fe84fd5a9d3314486e1a1457d0934a4255d + sass-listen (4.0.0) sha256=ae9dcb76dd3e234329e5ba6e213f48e532c5a3e7b0b4d8a87f13aaca0cc18377 + sawyer (0.9.3) sha256=0d0f19298408047037638639fe62f4794483fb04320269169bd41af2bdcf5e41 + securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 + simpleidn (0.2.3) sha256=08ce96f03fa1605286be22651ba0fc9c0b2d6272c9b27a260bc88be05b0d2c29 + terminal-table (1.8.0) sha256=13371f069af18e9baa4e44d404a4ada9301899ce0530c237ac1a96c19f652294 + typhoeus (1.5.0) sha256=120b67ed1ef515e6c0e938176db880f15b0916f038e78ce2a66290f3f1de3e3b + tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b + tzinfo-data (1.2025.3) sha256=b546e2f1e5e5c40a0c619aafb24e30d3d6a128c2f689278f721b7286dd499562 + unicode-display_width (1.8.0) sha256=0292132d364d59fcdd83f144910c48b3c8332b28a14c5c04bb093dd165600488 + uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 + wdm (0.2.0) sha256=c46d9dcb6d375199ca07465bc67669ee8f041aeaa55dd7dafe6de4dd97b27647 + webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131 + +BUNDLED WITH + 4.0.2 diff --git a/docs/Miscellaneous/FAQs.md b/docs/Miscellaneous/FAQs.md new file mode 100644 index 00000000..40af3411 --- /dev/null +++ b/docs/Miscellaneous/FAQs.md @@ -0,0 +1,316 @@ +--- +title: Frequently Asked Questions +nav_order: 2 +permalink: /FAQ/ +--- + +# twinBASIC Frequently Asked Questions + +### [General](#general) - [Installation](#installation) - [Using twinBASIC](#using-twinbasic) + +## General + +
+What is twinBASIC? + +twinBASIC is a new BASIC language and development environment (IDE) aiming to be 100% backwards compatible with VB6/VBA. + +
+ +
+Who is behind twinBASIC? + +twinBASIC is the work of Wayne Phillips, who operates the company [Everything Access](https://www.everythingaccess.com/), a well established provider of professional tools and services for Microsoft Access and VBA generally, including the popular vbWatchdog software. + +
+ +
+Where can I get twinBASIC? + +The latest version can be downloaded from the [Releases section](https://github.com/twinbasic/twinbasic/releases) of the [main twinBASIC GitHub repository](https://github.com/twinbasic/twinbasic). See [How do I install twinBASIC](#how-do-i-install-twinbasic) for more information on installation. + +
+ +
+What is the current status of the project? + +twinBASIC is currently late into the **Beta** stage, under development and not yet at a stable 1.0 release. All of the VB6/VBA7 syntax and intrinsic functions have been implemented. All of the basic controls except the OLE control, and about half of the Common Controls, have been implemented. It supports Forms, Classes, and UserControls-- both as compiled OCX/DLL controls and as in-project code (i.e. like .ctl files). However, not all features of these, such as properties, events, and methods, have been completed. Additionally, ActiveX EXEs and VBG project group support are not yet implemented, and there's a fair number of bugs remaining. + +However, **tB can already run many existing projects**, even fairly complex and large ones. Many community members have managed to get their apps and other open source apps up and running with little to no difficulty, and created new projects from scratch. Check out these examples for a good real world demonstrate of how far along the project is: + +Krool's [VBCCR](https://github.com/Kr00l/VBCCR) and [VBFlexGrid](https://github.com/Kr00l/VBFLXGRD) controls, Ben Clothier's [TwinBasicSevenZip](https://github.com/bclothier/TwinBasicSevenZip), Carles PV's [Lemmings](https://github.com/fafalone/Lems64), Don Jarrett's [basicNES](https://github.com/fafalone/basicNES) Nintendo emulator, and Jon Johnson's [ucShellBrowse/ucShellTree](https://github.com/fafalone/ShellControls), [FileActivityMon ETW Event Tracer](https://github.com/fafalone/EventTrace), [cTaskDialog](https://github.com/fafalone/cTaskDialog64), and [many more](https://github.com/fafalone). + +
+ +
+Is there an estimated timeline for when expected features will become available? + +Yes, see the [twinBASIC Roadmap](https://github.com/twinbasic/twinbasic/issues/335) in the Issues section for the latest update to the timeline. This roadmap only covers major components; smaller features are implemented in a less formal manner, usually when the related part of the codebase is being worked on. + +
+ +
+What new features does twinBASIC have compared to VB6? + +**Many!** It has 64bit compilation (using VBA7x64 compatible syntax), generics, overloading, multithreading (API-only right now, built in syntax coming soon), inheritance, ability to define interfaces and coclasses in your project using BASIC-style syntax, Unicode support in all controls and the editor (.twin files only), support for modern image formats, numerous enhancements to *Implements*, ability to create standard DLLs and kernel mode drivers, ability to set UDT packing alignment, and dozens of others, all available *right now*, with many more planned in the future. + +For a full list of all the new features available right now, see the Wiki article [Overview of features new to twinBASIC](twinBASIC-Features). + +
+ +
+Where can I learn more about twinBASIC, find documentation, and participate in the community? + +[twinBASIC Home Page](https://twinbasic.com) + +twinBASIC GitHub: [Main section](https://github.com/twinbasic/twinbasic) \| [Issues](https://github.com/twinbasic/twinbasic/issues) \| [Discussions](https://github.com/twinbasic/twinbasic/discussions) \| [Language Design](https://github.com/twinbasic/lang-design) \| [ Language Specification](https://github.com/twinbasic/lang-spec) \| [Documentation](https://docs.twinbasic.comi) + +[twinBASIC Discord](https://discord.gg/UaW9GgKKuE) + +[twinBASIC Forum on VBForums](https://www.vbforums.com/forumdisplay.php?108-TwinBASIC) + +
+ +
+ +Is twinBASIC Open Source? + +While open source models are possible in the future, at this time the compiler is not. There are plans in the works to open source the IDE. To address some of the major concerns this presents, once tB hits it first major release, the source code will be placed in escrow, to be released to the community in the event the author disappears or is unable to continue working on it due to death or serious illness/injury. + +
+ +
+How much does twinBASIC cost? + +There are 3 editions of twinBASIC: The Community Edition is FREE. A splash screen is placed on compiled 64bit binaries and certain features like advanced optimized compilation and future cross-platform compilation are unavailable, but there are no restrictions on core language features or royalties imposed. To get those features, subscriptions are available for the Professional and Ultimate editions. For more details, including current pricing for Professional and Ultimate editions, [see this page](https://twinbasic.com/preorder.html). + +Note that you can change the subscription level at any time and the community edition is always available. There will be no lockout (see [the previous statement regarding escrow](#is-twinbasic-open-source)) so you will always have the ability to develop, test and compile. + +
+ +
+Can I pay a one-time fee for a perpetual license? + +Due to the need for continuing income to be able to develop twinBASIC, subscriptions are the primary model for premium versions, which [are available](https://twinbasic.com/preorder.html) on a month-to-month or yearly basis. However, right now for a limited time, a buy-once perpetual license is available in the form of the [VIP Gold Lifetime Licence Initiative](https://twinbasic.com/vip.html). This provides not only a lifetime license to twinBASIC including updates and new versions, but numerous additional benefits available only to people who purchase this license. + +
+ +
+Can twinBASIC be used to develop commercial products, and what royalties are owed? + +There are no restrictions on any edition of twinBASIC; they can all be used to develop commercial products, on a ROYALTY FREE basis. Nothing is owed for selling programs or other products created with twinBASIC. The twinBASIC software itself, however, may not be redistributed without appropriate license. + +
+ +
+What does '100% backwards compatible' mean, technically? + +Backwards compatibility refers to matching all publicly documented syntax, included controls, component and control behavior, and control appearance. It does not include undocumented, proprietary internal implementation details. So for example all language keywords, functions, and methods are present and should give the same results, and Forms/Classes/UserControls should implement all the same publicly documented interfaces, but twinBASIC exe files are not internally structured in the same way, and there isn't compatibility with the undocumented VB project info structures in the exe, whose contents have been reverse engineered over the years by the community. + +Currently, all basic controls have reimplementations in twinBASIC that support Unicode and 64bit compilation except the OLE control; and a number of the primary Common Controls have also been reimplemented. Eventually, all controls shipped with VB6 Enterprise Edition will be reimplemented. Until that time, the original controls will still work in 32bit builds, and community members provide some alternatives, for example Krool's VBCCR controls and VBFlexGrid control all work and have 64bit-compatible twinBASIC versions. + +
+ +
+So some of my projects won't work? + +Most projects do not use these reverse engineered internals, but some do: most commonly, for self-subclassing and callbacks inside Forms/Classes/UserControls; and also for multithreading and inline assembly. These routines have native support in twinBASIC without requiring internals hacks, so replacing these small parts of a few programs is very simple: `AddressOf` is supported on class members, so you can use regular subclassing and callback methods as you would if they were in a .bas module. `CreateThread` can be called without any special steps. And tB supports statically linked .obj files allowing incorporation of code from other languages, inline assembly in the form of `Emit()`/`EmitAny()` to insert instructions, and further support is planned in the future. + +Additionally, twinBASIC redirects the most common msvbvm60.dll (also msvbvm50.dll/vbe6.dll/vbe7.dll) functions used as `Declare` statements by users, all of which also work in x64, if you add the `PtrSafe` keyword like any other DLL definition. The following functions currently have redirects: `VarPtr, GetMem1, GetMem2, GetMem4, GetMem8, PutMem1, PutMem2, PutMem4, PutMem8, __vbaObjSet, __vbaObjSetAddRef, __vbaObjAddRef, __vbaCastObj, __vbaCopyBytes, __vbaCopyBytesZero, __vbaRefVarAry`, and `__vbaAryMove`. You may continue to use these with `Declare` statements to support the particular signatures you prefer. Further, declares for olepro32.dll are redirected to identical functions in oleaut32.dll, as olepro32 was deprecated by NT4 and doesn't have a 64bit version. + +Other than those special cases, it's exceedingly rare for projects to depend on reverse engineered internals. So the vast majority of projects run with zero modification. + +
+ +
+ +How do I report bugs or other problems? + +The best way is to [create an issue](https://github.com/twinbasic/twinbasic/issues) in the twinBASIC GitHub repository. + +You can also create a post in the #bugs channel of the [twinBASIC Discord server](https://discord.gg/UaW9GgKKuE). + +
+ +
+Is the twinBASIC IDE available in other languages? + +The IDE currently has basic support for localizing all of the front end UI, with translations supplied by members of the community. These can be obtained from [#langpacks on the tB Discord server](https://discord.com/channels/927638153546829845/1329533568376115282), there's currently around 10 including French, German, Italian, Portuguese, Russian, Chinese (Simplified), Chinese (Traditional), Japanese, Swedish, Hungarian, Greek, Catalan, Indonesian (Bahasa), and Malayalam. Others may have been posted since this was written; check the channel. + +Internal text such as the hover information does not yet support localization, but this is planned for the future. + +
+ +## Installation + +
+What are the requirements for twinBASIC? + +The twinBASIC IDE is supported on Windows 7 through Windows 11. The installation is portable; you need only to extract the downloaded zip file then run; there's no installer. + +WebView2 is required. This is normally preinstalled on newer versions of Windows, and is installed along with Edge if you've installed that browser. You can also obtain it from [Microsoft's website](https://developer.microsoft.com/en-us/microsoft-edge/webview2?form=MA13LH#download-section). Select the Standalone Evergreen x86 version: + +![image](Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png) + + +
+ +
+twinBASIC won't run; says there's an invalid entry point. + +This issue is sometimes encountered on Windows 7. To be used on Windows 7, the OS must be fully updated; this error results from one or more missing updates. Run Windows Update to make sure you have all recent updates installed. If you still have problems, you can drop by the Discord or submit an issue on GitHub (see [`How do I report bugs or other problems?`](#how-do-i-report-bugs-or-other-problems)) + +
+ +
+ +How do I install twinBASIC? +tB does not require a full installation process, you need only extract the ZIP file. Download the latest version from the [Releases page](https://github.com/twinbasic/twinbasic/releases), named `twinBASIC_IDE_BETA_xxx.zip` (where xxx is a version number; click on 'Assets' to expand the file list if it's not already visible). + +![img](Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png) + +Download the zip and extract it to an **empty** folder. Do not simply overwrite a previous version; either delete everything in the folder or use a different one. Odd errors have been known to occur otherwise. It will run from this folder; some settings will be placed in AppData. + +
+ +
+How big is the twinBASIC installation? + +The IDE is quite small, it's currently only a 25MB download, about 80MB extracted, and that is half due to LLVM libraries. + +
+ +
+Where is twinBASIC IDE data stored? + +In addition to the directory you extract the IDE to, twinBASIC creates a folder in `%APPDATA%\Local\twinBASIC` and stores some settings in the Registry under `HKCU\Software\VB and VBA Program Settings\twinBASIC_IDE`. + +
+ +
+Is twinBASIC safe? (Some scanner) says it's malicious. + +Anyone who has ever tested their own programs against a wide variety of AV engines knows that unless your exe is 64bit and signed with a high-level certificate (and maybe not even then, until it's manually added to a trust list), false positives in a small number are simply a way of life. twinBASIC's IDE and compiler executables, like all apps in its position, may trigger a small number of positives on services like VirusTotal, particularly 32bit apps. These are almost always not from major vendors and/or "AI" based algorithmic detection. + +
+ +## Using twinBASIC + +
+How do I import my VB6 project into twinBASIC? + +The easiest way is through the import wizard. When you first start the twinBASIC IDE, you're presented with the New Project dialog- this contains an 'Import from VBP' option: + +![image](Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png) + +You can import individual files, from VB projects or any type, through the Import option on the Add menu, under Project or by right clicking the desired folder in the Project Explorer pane: + +![img](Images/2b32ab8c-fabc-4f42-9e6b-06e85574eaf4.png){:style="width:80%; height:auto;"} + +**NOTE:** You can select .bas/.cls files individually, but to import Forms, UserControls, Property Pages, and Resource Files you must currently select the .vbp file they're associated with. You'll then be shown a list of files you can import (with their new twinBASIC extensions .tbform/.twin etc-- make sure to import both, e.g. for Form1.frm you'll see Form1.frm.tbform and Form1.frm.twin: + +![img](Images/16833fae-4bd7-418f-bb16-691a611a5b01.png){:style="width:50%; height:auto;"} +
+ +
+Why do I see a lot of errors saying my variables are unrecognized? + +![image](Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png) + +While use is strongly recommended and considered a best practice, twinBASIC **does not** require `Option Explicit`. If you're seeing these errors, you may have overlooked a new feature of twinBASIC: automatically enabling `Option Explicit` project-wide. When you import a VB6 project, or create a new one, a small dialog pops up: + +![image](Images/05306a72-4ff6-427d-8970-969ef0c582e6.png) + +If you leave "Option Explicit ON" checked, that means it will be enforced project-wide, regardless of whether `Option Explicit` is used in the form/module/etc itself. If you uncheck it, you won't get any errors for it, just a warning: "This variable has been auto-declared by the compiler due to Option Explicit being OFF". If you want, you can disable that warning in Project Settings: + +![image](Images/2a1c71fd-f81c-4bd3-b61a-0f2979e8961f.png) + +For an existing project, the Project Scope Option Explicit can be turned on or off from Project Settings, under "Project: Option Explicit On": + +![image](Images/01009879-fdbc-4a8e-8683-353aab6193df.png) + +
+ +
+Does twinBASIC support addins? + +Addins for VB6 and VBA are not supported by the twinBASIC IDE. However, tB has its own powerful addin infrastructure based on modern web technologies. See Samples 10 through 16 in the 'Samples' tab of the New Project dialog: + +![image](Images/0e24eb5c-c9af-49a9-a908-03968b211554.png) + +twinBASIC supports **creating** addins for VBA. It's currently the only tool that supports creating these addins for 64bit Office using a language with 100% compatible syntax. See Sample 4 and Sample 5. + +
+ +
+How do I use resources in twinBASIC? + +Currently tB does not have a dedicated resource editor; instead, resources are managed through the Project Explorer. In the tree, you'll see a Resources folder; by default, it will include ICON in a Standard EXE, and MANIFEST, if you've chosen to enable Visual Styles: + +![image](Images/71ddde83-a091-47e3-b5b8-681954b0639d.png) + +You can create additional folders here, using their standard names. For example a BITMAP group could be added, then used with `LoadResImage`. Unlike its predecessor, tB does not restrict the type of resources: you can create any type of folder you want, and import binary data into it. For example, some community projects have inserted `UIFILE` resources for Ribbon controls and `DIALOG` resources for property sheets. Resources can be imported by right-clicking the folder you want them in, and selecting Add->Import file... from the menu. + +If you're importing a project, the resources in a linked .res file will be imported automatically. + +#### Strings + +String table resources are currently treated specially; they're edited in the IDE as JSON. If you import from VBP with a .res, string resources will be automatically converted. If you right click the 'Resources' folder, and go to the 'Add' submenu, at the bottom, you'll find "Add resource: String table" that adds one populated with example strings: + +![image](Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png) + +#### Group names + +If you create a new folder for a standard resource type, twinBASIC currently recognizes the following names, which you should use to create a folder under Resources: + +BITMAP +CUSTOM +CURSOR +ICON +MANIFEST +RCDATA +STRING +MESSAGETABLE + +For other standard types, you must use the # (pound sign) followed their number. For example, for DIALOG (RT_DIALOG) resources, do not name the folder dialog, it must be named `#5`. ANICURSOR would be named `#21`. And so on, for the [standard types](https://learn.microsoft.com/en-us/windows/win32/menurc/resource-types) with `RT_` constants. For any others, you can use any name you want, e.g. UIFILE can just be named UIFILE. + + +Note: At this time, .res files can only be imported as part of a VBP. + +
+ +
+How do I set my own icon for my program? + +By default newly created projects use the twinBASIC logo. +Imported projects use the icon of the Form chosen in Settings. This can be modified or set for all projects in the same way: in the Settings dialog for your project, there is an "Icon Form" option from which you can select which Form's icon will be used for your exe. + +If you don't set that option, or your project contains no Forms, the icon can be managed manually through the Resources folder. +If you're not already familiar with using resources in twinBASIC, see the FAQ entry right above this one. In this scenario, the icon used for your application in Explorer is the one in the Resources\ICON folder that comes first alphabetically. If you do not have an ICON folder in your project, you can create one by right-clicking the Resources folder and selecting Add->Add folder. + +![image](Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png) + +In the above picture, MyOwnIcon.ico would be used by Explorer and other apps to represent your .exe, as it comes before twinBASIC.ico alphabetically. + +Note that this will not be set as the icon of any form; icons for forms are set by the "Icon" property in the Properties list. + +You may set both the Icon Form option and include additional ICON resources. In this scenario, the Icon Form will take precedence- it will be inserted as #1, making it the first possible entry and therefore being used by Explorer. Do not use #1 for any of your additional icons in Resources in this scenario, the results may be unpredictable. + +
+ +
+What are the runtime requirements for twinBASIC-produced EXEs/binaries? + +Programs and modules/controls produced by twinBASIC have no native dependencies besides standard Windows system DLLs and are completely standalone/portable, besides of course 3rd party files your code may use. No runtime is required to be present. +Currently the minimum supported Windows version is **Windows XP**, with Windows 2000 support likely in the future. There are no current plans to support Windows ME, 98, 95, NT4, or earlier versions, as these lack key features for basic modernization provided by tB. +Certain new tB-exclusive features like child control transparency require newer versions only if they're used. +Everything should also work under WINE and ReactOS, but testing, while successful, has been minimal. Please share your experiences if you try this. + +
+ +
+Why are EXEs produced by twinBASIC larger than VB6? + +The large majority of functionality, including major pieces like the Forms engine, is provided in VB6 applications/components by the msvbvm60.dll runtime, a 1.4MB file. twinBASIC applications/components have no such outside dependency; the Forms engine and all other functionality is included in the single exe, so the combined size isn't too far off. EXE size is expected to be reduced significantly with the introduction of LLVM-optimized compilation, coming soon. + +
diff --git a/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.png b/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.png new file mode 100644 index 00000000..4786a543 Binary files /dev/null and b/docs/Miscellaneous/Images/01009879-fdbc-4a8e-8683-353aab6193df.png differ diff --git a/docs/Miscellaneous/Images/05306a72-4ff6-427d-8970-969ef0c582e6.png b/docs/Miscellaneous/Images/05306a72-4ff6-427d-8970-969ef0c582e6.png new file mode 100644 index 00000000..5600d3c5 Binary files /dev/null and b/docs/Miscellaneous/Images/05306a72-4ff6-427d-8970-969ef0c582e6.png differ diff --git a/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png new file mode 100644 index 00000000..9f4880da Binary files /dev/null and b/docs/Miscellaneous/Images/0e24eb5c-c9af-49a9-a908-03968b211554.png differ diff --git a/docs/Miscellaneous/Images/16833fae-4bd7-418f-bb16-691a611a5b01.png b/docs/Miscellaneous/Images/16833fae-4bd7-418f-bb16-691a611a5b01.png new file mode 100644 index 00000000..31edb871 Binary files /dev/null and b/docs/Miscellaneous/Images/16833fae-4bd7-418f-bb16-691a611a5b01.png differ diff --git a/docs/Miscellaneous/Images/2a1c71fd-f81c-4bd3-b61a-0f2979e8961f.png b/docs/Miscellaneous/Images/2a1c71fd-f81c-4bd3-b61a-0f2979e8961f.png new file mode 100644 index 00000000..f90f74df Binary files /dev/null and b/docs/Miscellaneous/Images/2a1c71fd-f81c-4bd3-b61a-0f2979e8961f.png differ diff --git a/docs/Miscellaneous/Images/2b32ab8c-fabc-4f42-9e6b-06e85574eaf4.png b/docs/Miscellaneous/Images/2b32ab8c-fabc-4f42-9e6b-06e85574eaf4.png new file mode 100644 index 00000000..a2d04478 Binary files /dev/null and b/docs/Miscellaneous/Images/2b32ab8c-fabc-4f42-9e6b-06e85574eaf4.png differ diff --git a/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png new file mode 100644 index 00000000..9eb7f20f Binary files /dev/null and b/docs/Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png differ diff --git a/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png new file mode 100644 index 00000000..5f009eef Binary files /dev/null and b/docs/Miscellaneous/Images/7e1cb69c-6db3-4f3f-aea1-c1fae25938a2.png differ diff --git a/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png new file mode 100644 index 00000000..51885b0c Binary files /dev/null and b/docs/Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png differ diff --git a/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png b/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png new file mode 100644 index 00000000..98f5941e Binary files /dev/null and b/docs/Miscellaneous/Images/94490c87-fafe-4d5b-ae39-d3cedba1c21d.png differ diff --git a/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png new file mode 100644 index 00000000..0397fcd9 Binary files /dev/null and b/docs/Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png differ diff --git a/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png new file mode 100644 index 00000000..d98bf734 Binary files /dev/null and b/docs/Miscellaneous/Images/ac019c1a-dcef-4964-a730-bc5b86c644ba.png differ diff --git a/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png new file mode 100644 index 00000000..826a9723 Binary files /dev/null and b/docs/Miscellaneous/Images/e409ea37-96ad-44c5-8017-3699ef04b53d.png differ diff --git a/docs/Packages/Creating a TWINPACK package.md b/docs/Packages/Creating a TWINPACK package.md new file mode 100644 index 00000000..801473f7 --- /dev/null +++ b/docs/Packages/Creating a TWINPACK package.md @@ -0,0 +1,88 @@ +--- +title: Creating a TWINPACK Package +parent: Packages +nav_order: 2 +permalink: /Packages/Creating-TWINPACK/ +--- + +# Creating a TWINPACK package + +To create a new TWINPACK package, navigate to the twinBASIC New Project dialog, and under the 'Samples' tab, choose the option labelled 'Package': + +![image](Images/6ad7a172-0e1b-4276-ac89-042681552507.png) +
+
+ +Once you've created the project, you should find the extra 'PACKAGE PUBLISHING' panel as a popup: + +![image](Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png) +
+
+ +You should now edit the Namespace, Description, Licence and Visibility properties appropriately by using the package manager 'EDIT' links, which will take you to the individual settings in the `Settings` file. Once you've edited them, remember to close (and save) the `Settings` file in order for your changes to be reflected in the package manager panel. + +- **Namespace:** this is the symbol that will be used to group your components in projects that reference your package. For example, a package that provides a series of different dialog classes might use the namespace `Dialogs`. +- **Description:** this is the descriptive text that will appear in the `Settings`->`References` list. If you plan to share this package, it is wise to think carefully about the description so that others can find your package easily through TWINSERV. +- **Licence:** this short text appears in the `Settings`->`References` list, alongside the Description. If you plan to share this package, it is important that you enter this field, and the value you enter here should appropriately match the content of the LICENCE.md file (e.g. 'MIT', 'LGPL' etc). +- **Visibility:** determines whether the package is visible to only you (PRIVATE) or everyone (PUBLIC). The value set here only takes effect when you use the 'PUBLISH THIS PACKAGE' button to publish your package in the package manager service, TWINSERV. + +*If you don't plan to publish your package on TWINSERV, then you don't need to fill in the **Licence** or **Visibility** fields.* + +You can now create components (Class, Module, Interface) in your project as normal, and when you are finished, it's time to finalize the package. You have two options; + +
+ +## OPTION 1 - Finalize the package into a TWINPACK file + +Use this option if you want to just create a local TWINPACK file that you can use in other projects. For this, the build process is the same as any ordinary twinBASIC build... just hit the Build button in the TWINBASIC toolbar: + +![image](Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png) +
+
+![image](Images/8d74d820-9907-4e76-ac42-71d0233187f1.png) + +You'll see the build output notification in the `DEBUG CONSOLE`, as seen above. + +Job done. See [Importing a package from a TWINPACK file](../Importing-TWINPACK) for referencing and using the TWINPACK file in other twinBASIC projects. + +
+ +## OPTION 2 - Publish the package directly to the package manager service (TWINSERV) + +If you're publishing your package onto TWINSERV, you don't need to create the TWINPACK file manually. Just use the 'PUBLISH THIS PACKAGE' button: + +![Create Package](Images/packPublishButton.png){:style="width:45%; height:auto;"} +
+
+ +***Publishing packages onto TWINSERV requires you to first create a publisher account. If you haven't done so, you'll be prompted to do so at this stage.*** + +You will then be prompted to confirm the package details: + +![Create Package](Images/packPublishPackage1.png){:style="width:65%; height:auto;"} +
+
+ +After pressing `YES`, the package will be uploaded to TWINSERV. Check the `DEBUG CONSOLE` for completion notices: + +![Create Package](Images/packPublishComplete1.png){:style="width:85%; height:auto;"} + +
+
+ + If the package got uploaded successfully, it should be available via TWINSERV within a few moments. If you've created a `PUBLIC` package, others will be able to see and download it at this point. + +See [Importing a package from TWINSERV](../Importing-TWINSERV) for referencing and using the uploaded packages. + +
+
+ +## Special files LICENCE.md and CHANGELOG.md + +When you create a new package project, you'll see two additional files created for you in the project filesystem: + +![Create Package](Images/packLicenceFiles.png){:style="width:55%; height:auto;"} +
+
+ +If you're publishing a `PUBLIC` package to the package manager service, it is important that you edit these two files before publishing. These are both markdown files, and will in future become more accessible to users that are considering using your package from TWINSERV. \ No newline at end of file diff --git a/docs/Packages/Images/0fa1272d-41d6-4d0f-b19c-f47f24a47c4d.png b/docs/Packages/Images/0fa1272d-41d6-4d0f-b19c-f47f24a47c4d.png new file mode 100644 index 00000000..b20baf93 Binary files /dev/null and b/docs/Packages/Images/0fa1272d-41d6-4d0f-b19c-f47f24a47c4d.png differ diff --git a/docs/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png b/docs/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png new file mode 100644 index 00000000..3d1e5d1e Binary files /dev/null and b/docs/Packages/Images/4d90f313-35d5-426d-8fc3-852ca03382fa.png differ diff --git a/docs/Packages/Images/4e4b8e4d-2a1c-42e5-8f4b-5a9b3f523ee8.png b/docs/Packages/Images/4e4b8e4d-2a1c-42e5-8f4b-5a9b3f523ee8.png new file mode 100644 index 00000000..fba9f46b Binary files /dev/null and b/docs/Packages/Images/4e4b8e4d-2a1c-42e5-8f4b-5a9b3f523ee8.png differ diff --git a/docs/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png b/docs/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png new file mode 100644 index 00000000..2710a91c Binary files /dev/null and b/docs/Packages/Images/6ad7a172-0e1b-4276-ac89-042681552507.png differ diff --git a/docs/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png b/docs/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png new file mode 100644 index 00000000..f8e13748 Binary files /dev/null and b/docs/Packages/Images/8d74d820-9907-4e76-ac42-71d0233187f1.png differ diff --git a/docs/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png b/docs/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png new file mode 100644 index 00000000..72ce0af6 Binary files /dev/null and b/docs/Packages/Images/9eeffbcf-d73e-4a92-bce5-811ed60aba98.png differ diff --git a/docs/Packages/Images/a1331a0e-3ba3-45cf-8dc3-2e24f0fa1fe6.png b/docs/Packages/Images/a1331a0e-3ba3-45cf-8dc3-2e24f0fa1fe6.png new file mode 100644 index 00000000..57ed4a99 Binary files /dev/null and b/docs/Packages/Images/a1331a0e-3ba3-45cf-8dc3-2e24f0fa1fe6.png differ diff --git a/docs/Packages/Images/d9f1e4d9-1805-47e5-93aa-251151b4e914.png b/docs/Packages/Images/d9f1e4d9-1805-47e5-93aa-251151b4e914.png new file mode 100644 index 00000000..3cfa26c8 Binary files /dev/null and b/docs/Packages/Images/d9f1e4d9-1805-47e5-93aa-251151b4e914.png differ diff --git a/docs/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png b/docs/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png new file mode 100644 index 00000000..e1347852 Binary files /dev/null and b/docs/Packages/Images/db4636f6-d988-4e31-94a2-c4c170418e81.png differ diff --git a/docs/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png b/docs/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png new file mode 100644 index 00000000..5900246a Binary files /dev/null and b/docs/Packages/Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png differ diff --git a/docs/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png b/docs/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png new file mode 100644 index 00000000..498aff9a Binary files /dev/null and b/docs/Packages/Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png differ diff --git a/docs/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png b/docs/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png new file mode 100644 index 00000000..3cfa26c8 Binary files /dev/null and b/docs/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png differ diff --git a/docs/Packages/Images/e9a3fd21-8e6a-4485-b52c-0c041600826b.png b/docs/Packages/Images/e9a3fd21-8e6a-4485-b52c-0c041600826b.png new file mode 100644 index 00000000..5900246a Binary files /dev/null and b/docs/Packages/Images/e9a3fd21-8e6a-4485-b52c-0c041600826b.png differ diff --git a/docs/Packages/Images/f2fd8374-fe46-40b0-8c66-2443df4dc5b3.png b/docs/Packages/Images/f2fd8374-fe46-40b0-8c66-2443df4dc5b3.png new file mode 100644 index 00000000..fba9f46b Binary files /dev/null and b/docs/Packages/Images/f2fd8374-fe46-40b0-8c66-2443df4dc5b3.png differ diff --git a/docs/Packages/Images/packLicenceFiles.png b/docs/Packages/Images/packLicenceFiles.png new file mode 100644 index 00000000..2c40fdcd Binary files /dev/null and b/docs/Packages/Images/packLicenceFiles.png differ diff --git a/docs/Packages/Images/packPublishButton.png b/docs/Packages/Images/packPublishButton.png new file mode 100644 index 00000000..7a9166ef Binary files /dev/null and b/docs/Packages/Images/packPublishButton.png differ diff --git a/docs/Packages/Images/packPublishComplete1.png b/docs/Packages/Images/packPublishComplete1.png new file mode 100644 index 00000000..ac0b1703 Binary files /dev/null and b/docs/Packages/Images/packPublishComplete1.png differ diff --git a/docs/Packages/Images/packPublishPackage1.png b/docs/Packages/Images/packPublishPackage1.png new file mode 100644 index 00000000..70d759a3 Binary files /dev/null and b/docs/Packages/Images/packPublishPackage1.png differ diff --git a/docs/Packages/Importing a package from TWINSERV.md b/docs/Packages/Importing a package from TWINSERV.md new file mode 100644 index 00000000..26923848 --- /dev/null +++ b/docs/Packages/Importing a package from TWINSERV.md @@ -0,0 +1,34 @@ +--- +title: Importing a Package from TWINSERV +parent: Packages +nav_order: 3 +permalink: /Packages/Importing-TWINSERV/ +--- + +# Importing a package from TWINSERV + +Open the project from which you want to use a package, open the `Settings` file within it and navigate to the References section. Select the 'Available Packages' button, and all packages that are on the server should be shown: + +![432410211-d9f1e4d9-1805-47e5-93aa-251151b4e914](Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png) +
+
+ +If you tick one of the available packages, it will be downloaded and imported into the project: + +![432416432-4e4b8e4d-2a1c-42e5-8f4b-5a9b3f523ee8](Images/f2fd8374-fe46-40b0-8c66-2443df4dc5b3.png) +
+
+ +Once you're finished, save and close the Settings file which will cause the compiler to be restarted. Now you're ready to use the package! In the example shown above I added a reference to the CSharpishStringFormater package, and I can now confirm that I can access components from the package in my code: + +![432417844-e9a3fd21-8e6a-4485-b52c-0c041600826b](Images/e2a65dfe-4a9d-4524-b6d6-7a6d1bc35cdb.png) +
+
+ +Note: If you have any PRIVATE packages that you have published, they are only available when signed in. If you are not already signed in, you will see a warning link that you can click to login: + +![image](Images/0fa1272d-41d6-4d0f-b19c-f47f24a47c4d.png) +
+
+ +After logging in, press the 'Available' button again to refresh the list. \ No newline at end of file diff --git a/docs/Packages/Importing a package from a TWINPACK file.md b/docs/Packages/Importing a package from a TWINPACK file.md new file mode 100644 index 00000000..7e81c6d1 --- /dev/null +++ b/docs/Packages/Importing a package from a TWINPACK file.md @@ -0,0 +1,37 @@ +--- +title: Importing a Package from a TWINPACK File +parent: Packages +nav_order: 4 +permalink: /Packages/Importing-TWINPACK/ +--- + +# Importing a package from a TWINPACK file + +To import a package directly from a TWINPACK file (instead of using TWINSERV), follow these steps. + +- open the project from which you want to use a package +- open the `Settings` file within it +- navigate to the References section +- select the 'Available Packages' button +![image](Images/d9f1e4d9-1805-47e5-93aa-251151b4e914.png) + +- press the 'Import from file...' button: + +![image](Images/e35d5955-9e70-4d6e-abd7-748558da75ba.png) + + + +- choose the TWINPACK file you want to import, and then it should appear in the references list (ticked): + +![image](Images/4e4b8e4d-2a1c-42e5-8f4b-5a9b3f523ee8.png) + +
+
+ +- Save the `Settings` and if needed restart the compiler + +Now you're ready to use the package! In the example shown above I added a reference to the CSharpishStringFormater package, and I can now confirm that I can access components from the package in my code: + +![image](Images/e9a3fd21-8e6a-4485-b52c-0c041600826b.png) +
+
\ No newline at end of file diff --git a/docs/Packages/Updating a package.md b/docs/Packages/Updating a package.md new file mode 100644 index 00000000..d70b4aba --- /dev/null +++ b/docs/Packages/Updating a package.md @@ -0,0 +1,36 @@ +--- +title: Updating a Package +parent: Packages +nav_order: 5 +permalink: /Packages/Updating/ +--- + +# Updating a package + +The compiler will notify you if a newer version of a package in your project is available on TWINSERV when you load your project: + +![image](Images/db4636f6-d988-4e31-94a2-c4c170418e81.png) + + +If you find an updated package is available on TWINSERV, you must first remove the old package from your project by deselecting it. Open Settings to References and untick the box. You will then be prompted to remove it from the filesystem: + +![415937809-87a11bc3-9a9c-4551-86c2-69d206d95087](Images/a1331a0e-3ba3-45cf-8dc3-2e24f0fa1fe6.png) +
+
+
+ +select "Remove it". + +Then go to the Available Packages tab and check the box for the latest version and **after it's done** downloading, which may take a few seconds since some packages are a few MB, Save Changes. In the Debug Console you'll first see + +`[PACKAGES] downloading package '{1FCDB98D-617D-4995-9736-2ED0E4746A10}/8/7/0/498' from the online database... ` + +then it's done and ready to be saved when a second message saying + +`[PACKAGES] downloading package '{1FCDB98D-617D-4995-9736-2ED0E4746A10}/8/7/0/498' from the online database... [DONE]` + +comes up. It will also go from the checkbox twirling to the entry being moved to the top (below built in packages) with `[IMPORTED]` prepended to it. + +Restart the compiler if it doesn't on its own after saving, but it usually does. + +**NOTE:** In the future there will be a simple update option. Keep an eye out for that change. \ No newline at end of file diff --git a/docs/Packages/What is a package.md b/docs/Packages/What is a package.md new file mode 100644 index 00000000..d7a9545c --- /dev/null +++ b/docs/Packages/What is a package.md @@ -0,0 +1,18 @@ +--- +title: What is a Package +parent: Packages +nav_order: 1 +permalink: /Packages/What-Is/ +--- + +# What is a package? + +In twinBASIC, a *package* is a collection of components that you can reference from another twinBASIC project. The components can be modules, classes or interfaces. + +A twinBASIC package is distributed as a TWINPACK file that contains everything needed by the components in that package. A project that references a TWINPACK package, imports the whole package into the file system of the root project, resulting in no external dependencies. + +With TWINPACK packages you group common components together into their own namespace whilst allowing for convenient code reuse without any of the problems often associated with using external DLL libraries. + +twinBASIC comes complete with a package manager service called TWINSERV, allowing you to easily share and distribute TWINPACK packages to other twinBASIC developers. + +Please be aware that TWINPACK files currently contain the full sourcecode of your packaged components. It is planned that we will in future allow for creating binary (compiled) TWINPACK files for developers that hold an Ultimate edition licence of twinBASIC. \ No newline at end of file diff --git a/docs/Packages/index.md b/docs/Packages/index.md new file mode 100644 index 00000000..f2e5793f --- /dev/null +++ b/docs/Packages/index.md @@ -0,0 +1,8 @@ +--- +title: Packages +nav_order: 4 +permalink: /Packages/ +--- + +# Packages + diff --git a/docs/Reference/Compiler Constants.md b/docs/Reference/Compiler Constants.md new file mode 100644 index 00000000..e9f00251 --- /dev/null +++ b/docs/Reference/Compiler Constants.md @@ -0,0 +1,115 @@ +--- +title: Compiler Constants +parent: Reference Section +nav_order: 2 +permalink: /Reference/Compiler-Constants/ +--- + +This is a guide to the built in compiler constants in twinBASIC. It includes the constants listed for VBA in its documentation even if they're not defined, as an undefined compiler constant can always be used, but will be 0. + +## `Win16` + +**Purpose:** Indicates a 16-bit Windows compatible platform.\ +**Value:** Always 0 (False); 16 bit Windows is not supported. + +## `Win32` + +**Purpose:** Indicates a 32bit compatible Windows platform\ +**Value:** Always 1 (True) on supported Windows platforms, for both 32bit and 64bit. + +## `Win64` + +**Purpose:** Indicates a 64bit Windows AMD64 platform.\ +**Value:** 0 (False) when the compiler is in 32bit mode, 1 (True) when in 64bit mode. + +## `VBA6` + +**Purpose:** Indicates compatibility with VBA6 syntax.\ +**Value:** Always 1 (True). + +## `VBA7` + +**Purpose:** Indicates compatibility with VBA7 syntax.\ +**Value:** Always 1 (True). + +## `MAC` +**Purpose:** Indicates running on a MacOS platform.\ +**Value:** Always 0 (False). Mac is not currently supported, although this will change in the future. + +## `TWINBASIC` + +**Purpose:** Indicates compatibility with twinBASIC syntax.\ +**Value:** Always 1 (True). + +## `TWINBASIC_BUILD` + +**Purpose:** Provides a `Long` value giving the current twinBASIC Build Number.\ +**Value:** Currently this is the same as the "BETA" number, e.g. for Beta 610 it will have a value of 610. + +## `TWINBASIC_BUILD_TYPE` +**Purpose:** Allows conditional compilation based on whether the project is an exe, dll, or ocx.\ +**Value:** A `String` that can be one of "Standard EXE", "Standard DLL", "ActiveX DLL", or "ActiveX Control", determined by the "Build Type" option in Project Settings. + + +# Usage + +Usage of these follows the standard syntax of using a hashtag before the standard `If/Else/ElseIf` conditionals. For example, to differentiate between 32bit and 64bit VBA vs 64bit twinBASIC, + +``` vb +#If VBA7 Then + 'We're in either VBA7 or twinBASIC + #If Win64 Then + 'We're in either 64bit VBA7 or 64bit twinBASIC + #If TWINBASIC Then + 'We're in 64bit twinBASIC + #If TWINBASIC_BUILD_TYPE = "ActiveX Control" Then + 'And we're building an OCX + #End If + #Else + 'We're in 64bit VBA7 + #End If + #Else + 'We're in either 32bit VBA7 or 32bit twinBASIC + #If TWINBASIC Then + 'We're in 32bit twinBASIC + #Else + 'We're in 32bit VBA7 + #End If + #End If +#Else + 'We're in VB6 or VBA6. Win64 will always be False by default. TWINBASIC will always be False by default. +#End If +``` + +Or more simply, to determine whether to use `PtrSafe` then `DeclareWide` or other tB features: + +``` vb +#If VBA7 Then + #If TWINBASIC Then + 'PtrSafe DeclareWide declares, if desired, also inline comments and `[ TypeHint() ]`, and function attributes. + #Else + 'PtrSafe declares not using DeclareWide or any new syntax + #End If +#Else + 'Classic VB6/VBA6 declares without PtrSafe or other new syntax +#End If +``` + +{: .important } +>Reminder: Compiler Constants are not `Boolean` values, so you shouuldn't use syntax like `#If Not Win64 Then` as the result may not be desired, for instance that example evaluates to `True` for both 32bit and 64bit modes when you likely used it expecting `False` under 64bit in order to use 32bit-only code.\ +If you wish to treat these as `Boolean`, you can use the `CBool()` function, e.g. `#If Not CBool(Win64) Then`. + +# Appearance + +The tB editor has the helpful feature of showing you in real time which compiler constants are active. Code in `#If` blocks is inactive and will appear grayed out if it will not execute under current settings. Note that unlike VBx, inactive code is not evaluated for errors. + +For example, in 32bit mode:\ +![image](Images/oHpCiV1.png) + +Then switching to 64bit mode:\ +![image](Images/TYizrRW.png) + + +--- +*VB6, VBA, VBA6, and VBA7 are trademarks of the Microsoft Corporation.*\ +*MacOS is a trademark of Apple, Inc.* diff --git a/docs/Reference/Images/TYizrRW.png b/docs/Reference/Images/TYizrRW.png new file mode 100644 index 00000000..4d345709 Binary files /dev/null and b/docs/Reference/Images/TYizrRW.png differ diff --git a/docs/Reference/Images/oHpCiV1.png b/docs/Reference/Images/oHpCiV1.png new file mode 100644 index 00000000..fe607960 Binary files /dev/null and b/docs/Reference/Images/oHpCiV1.png differ diff --git a/docs/Reference/index.md b/docs/Reference/index.md new file mode 100644 index 00000000..f0e5e14f --- /dev/null +++ b/docs/Reference/index.md @@ -0,0 +1,8 @@ +--- +title: Reference Section +nav_order: 7 +permalink: /Reference/ +--- + +# Reference Section + diff --git a/docs/WebView2/Customize the UserDataFolder.md b/docs/WebView2/Customize the UserDataFolder.md new file mode 100644 index 00000000..f6ab0838 --- /dev/null +++ b/docs/WebView2/Customize the UserDataFolder.md @@ -0,0 +1,21 @@ +--- +title: Customize the UserDataFolder +parent: WebView2 +nav_order: 2 +permalink: /WebView2/Customize-UserDataFolder/ +--- + +# Customize the UserDataFolder + +At runtime, WebView2 needs a working folder for storing data used during the session.  By default, a folder will be created in the same folder as your executable file, called `.WebView2` (e.g. `MyApp.Exe.WebView2`).  If this folder cannot be created, the WebView2 control will not work (you can catch the controls Error event to determine this at runtime). + +This default behaviour is not always appropriate.  For example, if you're creating an Addin for Microsoft Access, then you almost certainly will not be allowed to create a folder called `MSACCESS.EXE.WebView2` in the Office sub folder of your systems Program Files folder. + +It is HIGHLY recommended that you override the default behaviour, and instead provide a path that is considered to be safe to use for storing such data. To override the UserDataFolder path at runtime, handle the Create event of the WebView2 control.  See the example in `Sample 9. ActiveX Control WebView2 + Monaco` here, where we use the `%APPDATA%\Local` system path: + +![Create Package](Images/tbWebView2CreateEvent.png){:style="width:80%; height:auto;"} + +
+
+ +Set the `EnvironmentOptions.UserDataFolder` property to a string containing the output path to use (folder will be created if necessary). \ No newline at end of file diff --git a/docs/WebView2/Getting started.md b/docs/WebView2/Getting started.md new file mode 100644 index 00000000..4dc2b0d1 --- /dev/null +++ b/docs/WebView2/Getting started.md @@ -0,0 +1,47 @@ +--- +title: Getting Started +parent: WebView2 +nav_order: 1 +permalink: /WebView2/Getting-Started/ +--- + +# Getting Started + +## Package requirements + +To create projects that use WebView2, your projects must include both the `WinNativeForms` package and the `WebView2` package in your projects. + +Both of these packages can be added through the `Project` > `References` menu option, and selecting the `TWINPACK PACKAGES` button. Ensure both packages are ticked, and then close and save the Settings file and restart the compiler. + +![Create Package](Images/tbWebView2References.png){:style="width:45%; height:auto;"} +
+
+ +Once you've added the package references, you should find that the WebView2 control is now available to you in the form designer: + +![Create Package](Images/tbWebView2Toolbox.png){:style="width:15%; height:auto;"} +
+
+ +## Create a WebView2 control on a form + +We use the WebView2 control just like any ordinary control: + +![Create Package](Images/tbWebView2InAForm.gif){:style="width:60%; height:auto;"} +
+
+ +## WebView2 control properties + +There are lots of WebView2 properties and events to experiment with. + +![Create Package](Images/tbWebView2Properties.png){:style="width:45%; height:auto;"} +
+
+Note that toggling any property will show extra information at the bottom of the properties list to give you a little bit more information. For further information on a particular property, try searching the official
WebView2 documentation + +## Samples + +If you prefer to start with a sample, have a look at `Sample 0. WebView2 Examples`, available in the new-project dialog: + +![Create Package](Images/tbWebView2Sample0.png){:style="width:45%; height:auto;"} diff --git a/docs/WebView2/Images/tbWebView2CreateEvent.png b/docs/WebView2/Images/tbWebView2CreateEvent.png new file mode 100644 index 00000000..481fb5bb Binary files /dev/null and b/docs/WebView2/Images/tbWebView2CreateEvent.png differ diff --git a/docs/WebView2/Images/tbWebView2InAForm.gif b/docs/WebView2/Images/tbWebView2InAForm.gif new file mode 100644 index 00000000..a9c264b4 Binary files /dev/null and b/docs/WebView2/Images/tbWebView2InAForm.gif differ diff --git a/docs/WebView2/Images/tbWebView2Properties.png b/docs/WebView2/Images/tbWebView2Properties.png new file mode 100644 index 00000000..f37a9c47 Binary files /dev/null and b/docs/WebView2/Images/tbWebView2Properties.png differ diff --git a/docs/WebView2/Images/tbWebView2References.png b/docs/WebView2/Images/tbWebView2References.png new file mode 100644 index 00000000..2dc091a9 Binary files /dev/null and b/docs/WebView2/Images/tbWebView2References.png differ diff --git a/docs/WebView2/Images/tbWebView2Sample0.png b/docs/WebView2/Images/tbWebView2Sample0.png new file mode 100644 index 00000000..85d72223 Binary files /dev/null and b/docs/WebView2/Images/tbWebView2Sample0.png differ diff --git a/docs/WebView2/Images/tbWebView2Toolbox.png b/docs/WebView2/Images/tbWebView2Toolbox.png new file mode 100644 index 00000000..b4d3f284 Binary files /dev/null and b/docs/WebView2/Images/tbWebView2Toolbox.png differ diff --git a/docs/WebView2/Re-entrancy.md b/docs/WebView2/Re-entrancy.md new file mode 100644 index 00000000..4dc2b5ad --- /dev/null +++ b/docs/WebView2/Re-entrancy.md @@ -0,0 +1,22 @@ +--- +title: Information about Re-entrancy +parent: WebView2 +nav_order: 3 +permalink: /WebView2/Re-entrancy/ +--- + +# Information about re-entrancy + +The WebView2 API is very particular about not allowing for re-entrancy from its events (see Threading model for WebView2 apps). This means that when we process events such as `NavigationCompleted` we are ordinarily prohibited from doing anything with the WebView2 object model before returning from that event. So for example, you couldn't navigate to a new URL from within the `NavigivationCompleted` event itself. + +To work around these limitations, our WebView2 implementation defers all event handling by retriggering events through the form message loop. This allows events to be handled and execution control returns to WebView2 immediately, and then our deferred event gets triggered once WebView2 returns to the main message loop. + +Due to the design of our implementation, for the most part you can forget about the re-entrancy limitations imposed by the WebView2 API. However, if you use the `AddObject` feature of WebView2 which allows you to expose a twinBASIC class instance to javascript, then you need to be aware that there are two modes available for the `AddObject` feature. + +## AddObject(ObjectInstance As Object, UseDeferredInvoke As Boolean) + +If you pass `True` to the `UseDeferredInvoke` parameter of the `AddObject` call, then calls that come in to your class instance from javascript will be treated **asynchronously** and so you cannot return a value to javascript. This is great for event notifications. + +If you pass `False` to the `UseDeferredInvoke` parameter of the `AddObject` call, then calls that come in to your class instance from javascript will be treated **synchronously** and so you can return a value to be consumed by javascript, but you MUST ensure that you don't cause re-entrancy, so you MUST NOT make calls back into the WebView2 control methods and properties. Be warned: if you do make calls back into the WebView2 control when you're not using `UseDeferredInvoke`, then you will cause deadlocks leading to your application becoming unstable and sometimes lingering in the task manager after shutdown. + +Note that it is perfectly acceptable to add two separate objects, one for asynchronous event handling (using `UseDeferredInvoke:=True`) and another for synchronous properties (using `UseDeferredInvoke:=False`). \ No newline at end of file diff --git a/docs/WebView2/index.md b/docs/WebView2/index.md new file mode 100644 index 00000000..da604803 --- /dev/null +++ b/docs/WebView2/index.md @@ -0,0 +1,8 @@ +--- +title: WebView2 +nav_order: 5 +permalink: /WebView2/ +--- + +# WebView2 + diff --git a/docs/_config.yml b/docs/_config.yml index 39503867..e1aa40ae 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,21 +1,73 @@ url: twinbasic.github.io title: twinBASIC Documentation baseurl: / -remote_theme: pages-themes/slate@v0.2.0 -markdown: redcarpet -redcarpet: - extensions: ["no_intra_emphasis", "tables", "autolink", "strikethrough", "with_toc_data", "disable_indented_code_blocks"] + +# note: redcarpet is not supported on github pages +markdown: kramdown +kramdown: + parse_block_html: true + parse_span_html: true + input: GFM + #syntax_highlighter: rouge + +#remote_theme: pages-themes/slate@v0.2.0 +remote_theme: just-the-docs/just-the-docs@v0.10.1 + +highlighter: rouge + +plugins: +- jekyll-remote-theme + defaults: - scope: - path: "" + path: "*/Images" values: - layout: default -plugins: -- jekyll-remote-theme -collections: - intro: - output: true - features: - output: true - samples: - output: true \ No newline at end of file + image: true + +callouts: + tip: + title: 💡 Tip + color: green + important: + title: Important + color: purple + note: + title: Note + color: blue + warning: + title: warning + color: red + +#defaults: +# - scope: +# path: "" +# values: +# layout: default + +#collections: +# intro: +# output: true +# features: +# output: true +# samples: +# output: true + +# Exclude from processing. +# The following items will not be processed, by default. +# Any item listed under the `exclude:` key here will be automatically added to +# the internal "default list". +# +# Excluded items can be processed by explicitly listing the directories or +# their entries' file path in the `include:` list. +# +# exclude: +# - .sass-cache/ +# - .jekyll-cache/ +# - gemfiles/ +# - Gemfile +# - Gemfile.lock +# - node_modules/ +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/docs/_sass/custom/pygments-default.scss b/docs/_sass/custom/pygments-default.scss new file mode 100644 index 00000000..8070f2fb --- /dev/null +++ b/docs/_sass/custom/pygments-default.scss @@ -0,0 +1,61 @@ +.highlight .hll { background-color: #ffffcc } +.highlight .c { color: #408080; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #BC7A00 } /* Comment.Preproc */ +.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #808080 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0040D0 } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #7D9029 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #A0A000 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/docs/index.md b/docs/index.md index 657ad78b..a8af512e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,49 +1,50 @@ -# Work in progress... -Check back soon. The site is under active construction, please don't enter without a hard hat. - -

Table of Contents

- -{% assign mydocs = site.samples | group_by: 'category' %} -{% for cat in mydocs %} -{% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} -{% if catdata %} -

{{ catdata.title }}

-

{{ catdata.description }}

-{% else %} -

{{ cat.name }}

-{% endif %} -
    - {% assign items = cat.items | sort: 'order' %} - {% for item in items %} -
  • {{ item.title }}
  • - {% endfor %} -
-{% endfor %} - -
    -{% assign mydocs = site.samples | group_by: 'category' %} -{% for cat in mydocs %} -
  • -{% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} -
    -{% if catdata %} - {{ catdata.title }} -

    {{ catdata.description }}

    -
    -{% else %} - {{ cat.name }} -{% endif %} -{% assign items = cat.items | sort: 'order' %} - -
    -
  • -{% endfor %} -
\ No newline at end of file +--- +# Feel free to add content and custom Front Matter to this file. +# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults + +layout: home +title: Welcome +nav_order: 1 +permalink: / +--- + +# Welcome to twinBASIC + +## Frequently Asked Questions (FAQ) + +1. [twinBASIC FAQ](FAQ) + +## ActiveX +1. [HOW TO: Create a Custom ActiveX Control with twinBASIC](https://nolongerset.com/create-activex-control-with-twinbasic/) _[by Mike Wolfe @nolongerset]_ +2. [HOW TO: Create a Tool Window in the VBIDE with twinBASIC](https://nolongerset.com/create-a-vbe-addin-with-twinbasic/) _[by Mike Wolfe @nolongerset]_ + +## CustomControls +1. [Introduction](CustomControls/Introduction) +2. [Defining a CustomControl](CustomControls/Defining) +3. [Property sheet and object serialization](CustomControls/Properties) +4. [Painting / drawing to your control](CustomControls/Painting) +5. [Notes about the form designer](CustomControls/Notes) + +## Packages +1. [What is a package?](Packages/What-Is) +2. [Creating a TWINPACK package](Packages/Creating-TWINPACK) +3. [Importing a package from TWINSERV](Packages/Importing-TWINSERV) +4. [Importing a package from a TWINPACK file](Packages/Importing-TWINPACK) +5. [Updating a package](Packages/Updating) + +## WebView2 +1. [Getting Started](WebView2/Getting-Started) +2. [Customize the UserDataFolder](WebView2/Customize-UserDataFolder) +3. [Information about re-entrancy](WebView2/Re-entrancy) + +## Language and IDE Features +1. [Overview of features new to twinBASIC](Features/Overview) (compared to VBx) +2. [Control anchoring and docking ‐ Automatic size and position management](Features/Anchoring-Docking) +3. [Windowless vs. Windowed Controls in VBx and twinBASIC](Features/Windowless) + +## Reference Section + + +2. [List of available compiler constants](Reference/Compiler-Constants) diff --git a/docs/CNAME b/experiments/CNAME similarity index 100% rename from docs/CNAME rename to experiments/CNAME diff --git a/docs/TEST.md b/experiments/TEST.md similarity index 100% rename from docs/TEST.md rename to experiments/TEST.md diff --git a/experiments/_config.yml b/experiments/_config.yml new file mode 100644 index 00000000..39503867 --- /dev/null +++ b/experiments/_config.yml @@ -0,0 +1,21 @@ +url: twinbasic.github.io +title: twinBASIC Documentation +baseurl: / +remote_theme: pages-themes/slate@v0.2.0 +markdown: redcarpet +redcarpet: + extensions: ["no_intra_emphasis", "tables", "autolink", "strikethrough", "with_toc_data", "disable_indented_code_blocks"] +defaults: + - scope: + path: "" + values: + layout: default +plugins: +- jekyll-remote-theme +collections: + intro: + output: true + features: + output: true + samples: + output: true \ No newline at end of file diff --git a/docs/_data/meta/categories.json b/experiments/_data/meta/categories.json similarity index 100% rename from docs/_data/meta/categories.json rename to experiments/_data/meta/categories.json diff --git a/docs/_features/index.md b/experiments/_features/index.md similarity index 100% rename from docs/_features/index.md rename to experiments/_features/index.md diff --git a/docs/_includes/breadcrumbs.html b/experiments/_includes/breadcrumbs.html similarity index 100% rename from docs/_includes/breadcrumbs.html rename to experiments/_includes/breadcrumbs.html diff --git a/docs/_includes/lazyload.html b/experiments/_includes/lazyload.html similarity index 100% rename from docs/_includes/lazyload.html rename to experiments/_includes/lazyload.html diff --git a/docs/_includes/toc.html b/experiments/_includes/toc.html similarity index 100% rename from docs/_includes/toc.html rename to experiments/_includes/toc.html diff --git a/docs/_intro/index.md b/experiments/_intro/index.md similarity index 100% rename from docs/_intro/index.md rename to experiments/_intro/index.md diff --git a/docs/_layouts/default.html b/experiments/_layouts/default.html similarity index 100% rename from docs/_layouts/default.html rename to experiments/_layouts/default.html diff --git a/experiments/_samples/customcontrols/ccCOMCreatable.png b/experiments/_samples/customcontrols/ccCOMCreatable.png new file mode 100644 index 00000000..778b168e Binary files /dev/null and b/experiments/_samples/customcontrols/ccCOMCreatable.png differ diff --git a/experiments/_samples/customcontrols/ccClassIdAttribute.png b/experiments/_samples/customcontrols/ccClassIdAttribute.png new file mode 100644 index 00000000..0182a528 Binary files /dev/null and b/experiments/_samples/customcontrols/ccClassIdAttribute.png differ diff --git a/experiments/_samples/customcontrols/ccClassIdInsert.png b/experiments/_samples/customcontrols/ccClassIdInsert.png new file mode 100644 index 00000000..3d7868ab Binary files /dev/null and b/experiments/_samples/customcontrols/ccClassIdInsert.png differ diff --git a/experiments/_samples/customcontrols/ccCustomControlAttribute.png b/experiments/_samples/customcontrols/ccCustomControlAttribute.png new file mode 100644 index 00000000..bacbd7cb Binary files /dev/null and b/experiments/_samples/customcontrols/ccCustomControlAttribute.png differ diff --git a/experiments/_samples/customcontrols/ccGridButtonImage.png b/experiments/_samples/customcontrols/ccGridButtonImage.png new file mode 100644 index 00000000..1fc23423 Binary files /dev/null and b/experiments/_samples/customcontrols/ccGridButtonImage.png differ diff --git a/experiments/_samples/customcontrols/ccICustomControl.png b/experiments/_samples/customcontrols/ccICustomControl.png new file mode 100644 index 00000000..6c5dbc52 Binary files /dev/null and b/experiments/_samples/customcontrols/ccICustomControl.png differ diff --git a/experiments/_samples/customcontrols/ccSampleProject.png b/experiments/_samples/customcontrols/ccSampleProject.png new file mode 100644 index 00000000..e8dd13b7 Binary files /dev/null and b/experiments/_samples/customcontrols/ccSampleProject.png differ diff --git a/docs/_samples/customcontrols/defining.md b/experiments/_samples/customcontrols/defining.md similarity index 100% rename from docs/_samples/customcontrols/defining.md rename to experiments/_samples/customcontrols/defining.md diff --git a/docs/_samples/customcontrols/formdesigner.md b/experiments/_samples/customcontrols/formdesigner.md similarity index 100% rename from docs/_samples/customcontrols/formdesigner.md rename to experiments/_samples/customcontrols/formdesigner.md diff --git a/docs/_samples/customcontrols/index.md b/experiments/_samples/customcontrols/index.md similarity index 100% rename from docs/_samples/customcontrols/index.md rename to experiments/_samples/customcontrols/index.md diff --git a/docs/_samples/customcontrols/painting.md b/experiments/_samples/customcontrols/painting.md similarity index 100% rename from docs/_samples/customcontrols/painting.md rename to experiments/_samples/customcontrols/painting.md diff --git a/docs/_samples/customcontrols/propertysheetandserialization.md b/experiments/_samples/customcontrols/propertysheetandserialization.md similarity index 100% rename from docs/_samples/customcontrols/propertysheetandserialization.md rename to experiments/_samples/customcontrols/propertysheetandserialization.md diff --git a/docs/_samples/index.md b/experiments/_samples/index.md similarity index 100% rename from docs/_samples/index.md rename to experiments/_samples/index.md diff --git a/docs/_samples/packages/createpackage.md b/experiments/_samples/packages/createpackage.md similarity index 100% rename from docs/_samples/packages/createpackage.md rename to experiments/_samples/packages/createpackage.md diff --git a/docs/_samples/packages/importpackagefromfile.md b/experiments/_samples/packages/importpackagefromfile.md similarity index 100% rename from docs/_samples/packages/importpackagefromfile.md rename to experiments/_samples/packages/importpackagefromfile.md diff --git a/docs/_samples/packages/importpackagefromtwinserv.md b/experiments/_samples/packages/importpackagefromtwinserv.md similarity index 100% rename from docs/_samples/packages/importpackagefromtwinserv.md rename to experiments/_samples/packages/importpackagefromtwinserv.md diff --git a/docs/_samples/packages/index.md b/experiments/_samples/packages/index.md similarity index 100% rename from docs/_samples/packages/index.md rename to experiments/_samples/packages/index.md diff --git a/docs/_samples/packages/updatepackage.md b/experiments/_samples/packages/updatepackage.md similarity index 100% rename from docs/_samples/packages/updatepackage.md rename to experiments/_samples/packages/updatepackage.md diff --git a/docs/_samples/webview2/index.md b/experiments/_samples/webview2/index.md similarity index 100% rename from docs/_samples/webview2/index.md rename to experiments/_samples/webview2/index.md diff --git a/docs/_samples/webview2/reentrancy.md b/experiments/_samples/webview2/reentrancy.md similarity index 100% rename from docs/_samples/webview2/reentrancy.md rename to experiments/_samples/webview2/reentrancy.md diff --git a/docs/_samples/webview2/userdatafolder.md b/experiments/_samples/webview2/userdatafolder.md similarity index 100% rename from docs/_samples/webview2/userdatafolder.md rename to experiments/_samples/webview2/userdatafolder.md diff --git a/docs/assets/lazysizes.min.js b/experiments/assets/lazysizes.min.js similarity index 100% rename from docs/assets/lazysizes.min.js rename to experiments/assets/lazysizes.min.js diff --git a/docs/assets/treeview.css b/experiments/assets/treeview.css similarity index 100% rename from docs/assets/treeview.css rename to experiments/assets/treeview.css diff --git a/docs/images/twinBASICIconTransparent.png b/experiments/images/twinBASICIconTransparent.png similarity index 100% rename from docs/images/twinBASICIconTransparent.png rename to experiments/images/twinBASICIconTransparent.png diff --git a/experiments/index.md b/experiments/index.md new file mode 100644 index 00000000..657ad78b --- /dev/null +++ b/experiments/index.md @@ -0,0 +1,49 @@ +# Work in progress... +Check back soon. The site is under active construction, please don't enter without a hard hat. + +

Table of Contents

+ +{% assign mydocs = site.samples | group_by: 'category' %} +{% for cat in mydocs %} +{% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} +{% if catdata %} +

{{ catdata.title }}

+

{{ catdata.description }}

+{% else %} +

{{ cat.name }}

+{% endif %} +
    + {% assign items = cat.items | sort: 'order' %} + {% for item in items %} +
  • {{ item.title }}
  • + {% endfor %} +
+{% endfor %} + +
    +{% assign mydocs = site.samples | group_by: 'category' %} +{% for cat in mydocs %} +
  • +{% assign catdata = site.data.meta.categories | where:"category", cat.name | first %} +
    +{% if catdata %} + {{ catdata.title }} +

    {{ catdata.description }}

    +
    +{% else %} + {{ cat.name }} +{% endif %} +{% assign items = cat.items | sort: 'order' %} + +
    +
  • +{% endfor %} +
\ No newline at end of file diff --git a/docs/samples.md b/experiments/samples.md similarity index 100% rename from docs/samples.md rename to experiments/samples.md diff --git a/docs/sitemap.xml b/experiments/sitemap.xml similarity index 100% rename from docs/sitemap.xml rename to experiments/sitemap.xml