From e64c25ad70f1fefa307e87855df4eb3591c399f6 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 21:28:53 +0200 Subject: [PATCH 01/17] IDE: the Projects and files chapter (Project Explorer, Files and folders, Adding files, References and packages, Saving and exporting) absorbs Project Explorer and the File menu's Export Project, with redirects; File and Project menus as reference entries; callouts for the Project Explorer defects; SHOT markers for the pictures still to take --- WIP.IDE.md | 2 +- builder/page-baseline.json | 2 +- docs/Documentation/Book-Configuration.md | 2 +- docs/Features/Packages/Import-export tool.md | 8 +- docs/IDE/Code/Editor.md | 2 +- docs/IDE/Forms/Designer.md | 7 +- docs/IDE/Forms/index.md | 2 +- docs/IDE/Menu/File.md | 67 ++--- docs/IDE/Menu/Project.md | 29 ++- docs/IDE/Menu/View.md | 2 +- docs/IDE/New Project.md | 2 +- docs/IDE/Project Explorer.md | 211 --------------- docs/IDE/Project Settings.md | 6 +- docs/IDE/Projects/Adding-Files.md | 258 +++++++++++++++++++ docs/IDE/Projects/Files-and-Folders.md | 170 ++++++++++++ docs/IDE/Projects/Project-Explorer.md | 163 ++++++++++++ docs/IDE/Projects/References-and-Packages.md | 159 ++++++++++++ docs/IDE/Projects/Saving-and-Exporting.md | 171 ++++++++++++ docs/IDE/Projects/index.md | 57 ++++ docs/IDE/index.md | 2 +- docs/_book.yml | 10 +- 21 files changed, 1052 insertions(+), 280 deletions(-) delete mode 100644 docs/IDE/Project Explorer.md create mode 100644 docs/IDE/Projects/Adding-Files.md create mode 100644 docs/IDE/Projects/Files-and-Folders.md create mode 100644 docs/IDE/Projects/Project-Explorer.md create mode 100644 docs/IDE/Projects/References-and-Packages.md create mode 100644 docs/IDE/Projects/Saving-and-Exporting.md create mode 100644 docs/IDE/Projects/index.md diff --git a/WIP.IDE.md b/WIP.IDE.md index b9f12db9..fbb4d9e6 100644 --- a/WIP.IDE.md +++ b/WIP.IDE.md @@ -31,7 +31,7 @@ children. Second person ("you") is allowed here, as in tutorials. |---|---|---|---| | 1 | A tour of the IDE (landing page) | `/tB/IDE` | `index.md` | | 2 | Starting a project | `/tB/IDE/Starting` | New Project, Splash Screen, FAQ's first-launch and VBP-import parts | -| 3 | Projects and files | `/tB/IDE/Projects` | Project Explorer (file and object views, Add, context menu, resource editors), references and packages (links to Features/Packages), Export Project (from Menu/File) | +| 3 | Projects and files | `/tB/IDE/Projects` | Project Explorer (file and object views, Add, context menu; no resource editors: images preview, the rest open as text), references and packages (links to Features/Packages), Export Project (from Menu/File) | | 3a | Project Settings (reference) | `/tB/IDE/Project-Settings` | `Project Settings.md`, kept whole; **its anchors stay**, as 19 links use them | | 4 | Writing code | `/tB/IDE/Code` + children | Editor, Find/Replace, Outline, Open Editors, History, Diagnostics, `Features/Compiler-IDE/CodeLens` | | 5 | Designing forms and reports | `/tB/IDE/Forms`, `/tB/IDE/Reports` | tbForm, Toolbox, Properties, the Format menu's operations, tbReport | diff --git a/builder/page-baseline.json b/builder/page-baseline.json index 2c0f3f36..cf187a43 100644 --- a/builder/page-baseline.json +++ b/builder/page-baseline.json @@ -1,5 +1,5 @@ { "src": "docs", - "pages": 1248, + "pages": 1253, "staticFiles": 1009 } diff --git a/docs/Documentation/Book-Configuration.md b/docs/Documentation/Book-Configuration.md index d615d100..290bea06 100644 --- a/docs/Documentation/Book-Configuration.md +++ b/docs/Documentation/Book-Configuration.md @@ -87,7 +87,7 @@ These are warnings: the exit code does not change. A build with nothing to repor A link from inside the book to a left-out page opens that page on the website, since a site path goes nowhere in a PDF. The link check's pass over `book.html` lists each such link as `OUT OF BOOK`: _site-pdf/book.html: - OUT OF BOOK https://docs.twinbasic.com/tB/IDE/Project/Explorer -- not in the book; opens the website + OUT OF BOOK https://docs.twinbasic.com/tB/IDE/Project/PackagePublishing -- not in the book; opens the website Look there first for a left-out page that belongs in the book after all. diff --git a/docs/Features/Packages/Import-export tool.md b/docs/Features/Packages/Import-export tool.md index 2e0f98fa..11d31512 100644 --- a/docs/Features/Packages/Import-export tool.md +++ b/docs/Features/Packages/Import-export tool.md @@ -130,7 +130,7 @@ stops at the first folder inside `Packages\`: it writes nothing, prints neither like this, among them the **WinNativeCommonCtls** package and the *Standard EXE (plus VBCCR v1.8)* template. The script packs them. An export made by the IDE's **File → Export Project** stops the same way, because it holds the compiler packages under `Packages\`; see [Packing -the export back into a project](../../tB/IDE/Reference/Menu/File#packing-the-export-back-into-a-project). +the export back into a project](../../tB/IDE/Projects/Saving-and-Exporting#packing-the-export-back-into-a-project). **The script's `import` adds the folders the IDE always writes.** Every project and package the IDE exports has `ImportedTypeLibraries`, `Miscellaneous`, `Packages`, `Resources` and `Sources` @@ -193,7 +193,7 @@ IDE](#keeping-a-project-in-git-from-the-ide). > folder of its own, as the next section does. Its export also holds the source of the > compiler packages, and the tB executable cannot pack that export back into a project while > any folder remains under its `Packages`. See -> [Export Project](../../tB/IDE/Reference/Menu/File#export-project). +> [Export Project](../../tB/IDE/Projects/Saving-and-Exporting#export-project). The steps, in order: @@ -259,7 +259,7 @@ them too. > Keep *Export Path* on a folder of its own. Every export deletes everything in its folder > before it writes, a `.git` folder included, so never set it to the repository's top folder > or to the folder that holds the `.twinproj`. See -> [Export Project](../../tB/IDE/Reference/Menu/File#export-project). +> [Export Project](../../tB/IDE/Projects/Saving-and-Exporting#export-project). **Make the folder that holds the `.twinproj` the repository's top folder**, with `git init` there. Once the project has been saved and the `.gitignore` below added, it holds: @@ -291,7 +291,7 @@ they become a copy inside the project that the compiler ignores, and every later writes that copy back into `src\Packages`. So after an IDE update, a repository that holds them keeps the package source of the IDE that first exported them, while the project compiles against the packages of the IDE in use. [Packing the export back into a -project](../../tB/IDE/Reference/Menu/File#packing-the-export-back-into-a-project) has the +project](../../tB/IDE/Projects/Saving-and-Exporting#packing-the-export-back-into-a-project) has the measurements. Those four are the compiler packages of a Standard EXE with the default references. Add a diff --git a/docs/IDE/Code/Editor.md b/docs/IDE/Code/Editor.md index 1c16a072..abf94121 100644 --- a/docs/IDE/Code/Editor.md +++ b/docs/IDE/Code/Editor.md @@ -330,7 +330,7 @@ The key beside an action in the palette is the key Monaco gives it. It is not al ## Save often -The IDE keeps no backup of your edits. If the IDE or the PC stops before you save, the edits made since the last save are lost. Nothing is offered when you open the project again. Save with [**File → Save Project**](../Reference/Menu/File) (Ctrl+S), and save often. The IDE saves the whole project at once. **Save Current Document**, on the same menu, is disabled. +The IDE keeps no backup of your edits. If the IDE or the PC stops before you save, the edits made since the last save are lost. Nothing is offered when you open the project again. Save with [**File → Save Project**](../Projects/Saving-and-Exporting#save-project) (Ctrl+S), and save often. The IDE saves the whole project at once. **Save Current Document**, on the same menu, is disabled. What the IDE does keep, every five seconds, is the state of the project's editors: which files are open, the cursors and folds, the bookmarks and the History list. It is kept with the project and brought back when you reopen it. It holds none of your unsaved text. diff --git a/docs/IDE/Forms/Designer.md b/docs/IDE/Forms/Designer.md index ed064ee8..f8dc2bce 100644 --- a/docs/IDE/Forms/Designer.md +++ b/docs/IDE/Forms/Designer.md @@ -11,8 +11,9 @@ index: - zoom, form designer - lock controls - tab order - - View As JSON - Object Designer +index_also: + - View As JSON --- # Designer @@ -21,7 +22,7 @@ A form is two files, a designer file and a code file. This page describes how to ## Add a form -The **Add** menu creates a form. It is in the right-click menu of the [Project Explorer](../Project/Explorer), and in the **Project** menu. The Windows items and the CustomControls item are always shown, whether the project refers to their package or not. +The **Add** menu creates a form. It is in the right-click menu of the [Project Explorer](../Projects/Project-Explorer), and in the **Project** menu. [Adding files](../Projects/Adding-Files) describes the menu. The Windows items and the CustomControls item are always shown, whether the project refers to their package or not. | Item | Creates | Package it needs | |---|---|---| @@ -93,7 +94,7 @@ A form's designer file and its `.twin` file belong together. Renaming one in the ### View a form as JSON -**View As JSON** in the Project Explorer's right-click menu shows the designer file as text. It is in the menu for `.tbform`, `.tbcontrol`, `.tbppage` and `.tbreport` files and for the files in a package, and it is hidden when more than one item is selected. The text opens in a read-only tab titled `JSON: 'frmMain.tbform':`. A comment at its top gives the `URI:` of the file and the `SNAPSHOT:` time. The tab is a snapshot and does not follow later changes, but it includes the changes in the designer that you have not saved yet. +**View As JSON** in the Project Explorer's right-click menu shows the designer file as text. It is in the menu for `.tbform`, `.tbcontrol`, `.tbppage` and `.tbreport` files and for the files in a package, and it is greyed out when a designer file is selected together with other items. The text opens in a read-only tab titled `JSON: 'frmMain.tbform':`. A comment at its top gives the `URI:` of the file and the `SNAPSHOT:` time. The tab is a snapshot and does not follow later changes, but it includes the changes in the designer that you have not saved yet. ## Switch between design and code diff --git a/docs/IDE/Forms/index.md b/docs/IDE/Forms/index.md index 2a891e57..dd3e7f9e 100644 --- a/docs/IDE/Forms/index.md +++ b/docs/IDE/Forms/index.md @@ -59,6 +59,6 @@ Two kinds of setting differ in where they live. The grid, the outlines and the l ## See Also - [Writing code](../Code/) -- the code editor, for the `.twin` half of a form -- [Project Explorer](../Project/Explorer) -- the **Add** menu that creates forms +- [Adding files](../Projects/Adding-Files) -- the **Add** menu that creates forms - [Running and debugging](../Debugging/) -- running a program that shows forms - [Customising the IDE](../Customising/IDE-Options#form-designer-and-toolbox) -- the options of the designer and the Toolbox diff --git a/docs/IDE/Menu/File.md b/docs/IDE/Menu/File.md index 011d3654..556f2e9d 100644 --- a/docs/IDE/Menu/File.md +++ b/docs/IDE/Menu/File.md @@ -10,58 +10,47 @@ redirect_from: # File Menu -![The File menu open below the menu bar. New Project with CTRL+N, Open Project with CTRL+O, Open Recent, and Exit with ALT+F4 are available; Close Project, Save Project, Save Project As, Export Project with CTRL+E, Save Current Document, Build and Clean are all greyed out.](Images/Menu_File.png){:width="190" height="337"} +The File menu holds the commands that open, save, close, export and build a project. [Saving and exporting](../../Projects/Saving-and-Exporting) explains the first four. -## Export Project +![The File menu open below the menu bar with no project loaded, in five groups divided by lines. New Project, Open Project, Open Recent and Exit are available, and every other item is greyed out. Each item has an icon except Open Recent and Close Project, and five show a key at the right: Ctrl+N, Ctrl+O, Ctrl+S, Ctrl+E and Alt+F4.](Images/Menu_File.png){:width="190" height="337"} -Writes the open project out to a folder as separate files, instead of the single `.twinproj` file. The folder gets the project's `Settings` file, its `Sources`, `Resources` and other folders, and a `Packages` folder with the full source of every package the project references. For a small project that uses the **VB** package, the export held 477 files: two of the project's own, and 475 under `Packages`. Ctrl+E runs the same command. +The commands from **Close Project** to **Clean** work on the open project, and are greyed out when none is open. -**Before it writes anything, the command deletes everything already in the target folder.** It does not ask first, and the deleted files do not go to the Recycle Bin. Files that have nothing to do with the project are deleted too: hidden files, a `.git` folder, anything else there. +## Open and close -> [!WARNING] -> Point **Export Project** only at a folder that holds nothing but an earlier export of the same project. Never point it at a folder that holds anything else, at the top folder of a Git repository, or at the folder that holds the `.twinproj` file. +**New Project...** (Ctrl+N) and **Open Recent...** +: Open the **New / Open Project** dialog, on its **New** tab and on its **Recent** tab. Nothing is closed until you press **Open** in it. See [New Project](../../Project/New) and [Open a project](../../Projects/Saving-and-Exporting#open-a-project). -### Where it writes +**Open Project...** (Ctrl+O) +: Opens a project file, or a `.vbp` file, which is imported as a new project. See [Open a project](../../Projects/Saving-and-Exporting#open-a-project). -- **With [*Export Path*](../../Project-Settings#export-path) set**, the command exports there straight away, with no dialog. -- **With no *Export Path***, it opens a *Browse For Folder* dialog, which starts in the folder that holds the `.twinproj`. The export goes into a subfolder of the chosen folder named after the project, and it is that subfolder that is emptied. For a project named `MyApp`, choosing `C:\Work` exports into `C:\Work\MyApp\`. If the project itself is kept in `C:\Work\MyApp\`, choosing `C:\Work` empties the project's own folder. +**Close Project** +: Closes the project, after a question if it has unsaved changes. It has no key. See [Close Project and Exit](../../Projects/Saving-and-Exporting#close-project-and-exit). -With [*Export After Save*](../../Project-Settings#export-after-save) set, every save runs the export again, into *Export Path*, and empties that folder again. +**Exit** (Alt+F4) +: Closes the project, after the same question, and ends the IDE. -### When a file cannot be deleted +## Save -A read-only file stops the export part-way. Everything before it in alphabetical order is already deleted by then, everything after it is left, and nothing is written. No message appears. The only record is in the [Debug Console](../../Debugging/Debug-Console): +**Save Project** (Ctrl+S) +: Saves the whole project, with every open editor. For a project with no file, it asks for one first. See [Save Project](../../Projects/Saving-and-Exporting#save-project). -```text -[EXPORT] DELETE FAILED: \\?\C:\Work\MyApp\notes.txt -[EXPORT] ERROR: unable to clean the output folder -[EXPORT] export failed. -``` +**Save Project As...** +: Saves the project to a file that you choose, and keeps that file as the project's. It has no key. See [Save Project As](../../Projects/Saving-and-Exporting#save-project-as). -Git makes the files in `.git\objects` read-only. When the target is the top folder of a repository, the command deletes `.git\config`, `HEAD`, `index`, `hooks` and `info`, then stops at the first object file. Git no longer recognises what is left as a repository. +**Save Current Document** +: Is always greyed out, and has no key. The IDE saves the whole project, not one file. -### Exporting into the project's own folder +## Export -When the target is the folder that holds the `.twinproj`, the command deletes the `.twinproj` file too. The project then exists only in the open IDE, until **Save Project** (Ctrl+S) writes the file back. For this reason the Project Settings dialog refuses `${SourcePath}` on its own as the *Export Path*, but it accepts the same folder written out in full. +**Export Project...** (Ctrl+E) +: Writes the project out to a folder as separate files, after it deletes everything in that folder. See [Export Project](../../Projects/Saving-and-Exporting#export-project), and read its warning first. -### Packing the export back into a project +## Build and Clean +{: #build } -The `Packages` folder holds the compiler packages as well. For a project with the default references they are **VB**, **VBA**, **VBRUN** and the package behind the **App** object, in folders named `VB`, `VBA`, `VBRUN` and `AppGlobalClassProject`. Every other compiler package the project references gets a folder too, named after the package's own project, which is not always the name the reference uses: the WebView2 sample references `WebView2Package` and `WindowsControlsPackage`, and its export has folders named `WebView2Package` and `VB`, because `WindowsControlsPackage` is the VB package. The project's `Settings` file marks each compiler package's reference `"isCompilerPackage": true`; nothing inside the package's own folder does. +**Build** +: Compiles the project into the file that the [*Build Output Path*](../../Project-Settings#build-output-path) setting names. The project templates set it to `${SourcePath}\Build\${ProjectName}_${Architecture}.${FileExtension}`, a file in a `Build` folder beside the `.twinproj`. `${Architecture}` is `win32` or `win64`, as chosen in the [build configuration](../Toolbar#build-configuration) box on the toolbar. It has no key. -A `.twinproj` file that the IDE saved does not hold the compiler packages, and the `export` command of the tB executable does not write them. A package the project embeds is different: one added from TWINSERV or from a TWINPACK file is embedded by default (see [Linked Packages](../../../../Features/Packages/Linked)), is part of the saved `.twinproj`, and has a folder under `Packages` too. - -**Delete the compiler packages' folders before packing the export back into a project.** The IDE's own way to pack it is **Import from folder...** in the [New Project](../../Project/New#import-from-folder) dialog, which opens the project unsaved; the first save asks for a file name. The [import/export script](../../../../Features/Packages/Import-Export-Tool#usage)'s `import` packs it as well. Both pack every folder under `Packages` into the project, so the compiler packages become a copy inside it. Rebuilt by **Import from folder** with them, the project was 4,222,833 bytes, against 4,207 bytes without them and 2,956 bytes for the project as the IDE saved it. Both rebuilt projects open with no errors, and the script's project is the same 4.2 MB. - -The compiler does not use that copy. A function added to the copy of **VBA**, in `Packages\VBA\Sources\Math.twin`, is an unrecognized symbol (TB5079) to the code that calls it. But every later export writes the copy back into `Packages`: the added function is there again after each save, and the Debug Console reports `[EXPORT] COMPLETED (139 folders, 954 files)`, where the original project's export reported `(72 folders, 479 files)`. So after an IDE update, the export still holds the package source of the IDE that first exported the project, while the project compiles against the packages of the IDE in use. - -The tB executable's `import` cannot pack a folder while any folder remains under `Packages\`. It stops at the first one, writes nothing, and exits with code `999` --- see [Where the two differ](../../../../Features/Packages/Import-Export-Tool#where-the-two-differ). With the compiler packages' folders deleted, it packs the export of a project that embeds no package. [Keeping a project in Git from the IDE](../../../../Features/Packages/Import-Export-Tool#keeping-a-project-in-git-from-the-ide) keeps them out of the repository from the start. - -### What the Debug Console shows - -Each export writes a first line, `[EXPORT] exporting current project to "…"`, and a last line: `[EXPORT] COMPLETED (72 folders, 478 files)`, or the failure lines above. With [*Export Verbose*](../../Project-Settings#export-verbose) set, it also writes a line for each file and folder it deletes, `[EXPORT] DELETED: …`, and for each file it writes, `[EXPORT] DONE: …`. - -The `export` command of the tB executable and of the import/export script deletes nothing. See [What both programs do](../../../../Features/Packages/Import-Export-Tool#what-both-programs-do). - -## Build - -Compiles the project into the file that the [*Build Output Path*](../../Project-Settings#build-output-path) setting names. The project templates set it to `${SourcePath}\Build\${ProjectName}_${Architecture}.${FileExtension}`, a file in a `Build` folder beside the `.twinproj`. `${Architecture}` is `win32` or `win64`, as chosen in the [build configuration](../Toolbar#build-configuration) box on the toolbar. +**Clean** +: Deregisters the previously built DLL, if there is one, and deletes the previous build file. It has no key. diff --git a/docs/IDE/Menu/Project.md b/docs/IDE/Menu/Project.md index 19d14c53..dfdec5df 100644 --- a/docs/IDE/Menu/Project.md +++ b/docs/IDE/Menu/Project.md @@ -10,21 +10,32 @@ redirect_from: # Project Menu -![The Project menu open with every command greyed out: Add, which carries a submenu arrow, References with CTRL+T, Project Settings, Open Project Folder and Open Build Output Folder.](Images/Menu_Project.png){:width="200" height="169"} +The Project menu holds the commands that add to the project, change its references and settings, and open its folders. [Projects and files](../../Projects/) explains them. -## Add +![The Project menu open with every command greyed out, because no project is open. Add has a submenu arrow, and References shows its key.](Images/Menu_Project.png){:width="200" height="169"} + +Every command needs an open project, and is greyed out until one is. -**Add** is the same as Right Click Add on the [Project Explorer](../../Project/Explorer) +## Add -![The Project Explorer context menu with Add highlighted and its submenu opened out to the left. The submenu lists Add Folder; five Windows item types from Form through MDI Form, UserControl and PropertyPage to Report; Add CustomControls Form; the Unicode-capable .TWIN module and class; the .BAS module and .CLS class; Add Other File; Import; and three Add Resource entries for a Visual Styles Manifest, a String Table and a MESSAGETABLE. On the parent menu, Cut, Copy, Paste, View As JSON and View As Markdown Preview are greyed out.](../Images/RightClick-Add.png){:width="510" height="492"} +**Add** +: Opens the submenu of things to add: a folder, forms and other designers, modules and classes, other files, imports and three resources. It lists the same items as the **Add** entry of the right-click menu of the Project Explorer. See [Adding files](../../Projects/Adding-Files). -## References +## References and settings {: index_also="add reference" } -See [Project Settings](../../Project-Settings) filtered by "project.references". +**References...** (Ctrl+T) +: Opens [Project Settings](../../Project-Settings) with the filter `project.references`, so that only the **Library References** section shows. See [References and packages](../../Projects/References-and-Packages). + +**Project Settings...** +: Opens the whole [Project Settings](../../Project-Settings) dialog. It has no key. + +## Folders -![The Project Settings dialog with project.references in its filter box, showing the Library References section on its Enabled Libraries tab. Four ticked rows are listed in priority order against Library Symbol and Version columns: the twinBASIC VBA and VBRUN compatibility packages, OLE Automation as stdole, and the IDE Extensibility package as tbIDE.](../Images/ProjectSettings_LibraryReferences.png){:width="1102" height="774"} +**Open Project Folder...** +: Opens the folder of the project's `.twinproj` file in Windows Explorer. For a project that has no file yet, it shows the notification **Project is not yet saved. Please save the project first.** It has no key. -## Project Settings +**Open Build Output Folder...** +: Opens the folder of the file that the [Build Output Path](../../Project-Settings#build-output-path) names. It does not create the folder, and it gives the same notification when the project has no file or no build output path. It has no key. -See [Project Settings](../../Project-Settings). +See [Open a folder](../../Projects/Saving-and-Exporting#open-a-folder). diff --git a/docs/IDE/Menu/View.md b/docs/IDE/Menu/View.md index 2c8eb9fa..534aee6c 100644 --- a/docs/IDE/Menu/View.md +++ b/docs/IDE/Menu/View.md @@ -49,7 +49,7 @@ The last seventeen items show a panel. A panel that is in no layout in use comes : The code editor. See [Writing code](../../Code/). **PROJECT EXPLORER** -: The files and objects of the project. See [Project Explorer](../../Project/Explorer). +: The files and objects of the project. See [Project Explorer](../../Projects/Project-Explorer). **OPEN EDITORS**, **HISTORY** and **OUTLINE** : The open files, the places where you edited, and the symbols of the current file. See [Navigating](../../Code/Navigating). diff --git a/docs/IDE/New Project.md b/docs/IDE/New Project.md index 0ec4fd42..d5702fea 100644 --- a/docs/IDE/New Project.md +++ b/docs/IDE/New Project.md @@ -34,7 +34,7 @@ Opens a project from a folder of source files, such as the folder that **File The project opens with no `.twinproj` file behind it: it is unsaved, and marked as changed. Because it has no file, the first **Save Project** (Ctrl+S) opens the *Save As* dialog to ask for one. The folder it is saved in becomes `${SourcePath}`, which the project's [*Export Path*](../Project-Settings#export-path) may use. -If the folder holds the compiler packages under `Packages`, as an export by the IDE does, delete their folders first: imported with them, the project gets a copy of them that the compiler does not use. See [Packing the export back into a project](../Reference/Menu/File#packing-the-export-back-into-a-project). [Keeping a project in Git from the IDE](../../../Features/Packages/Import-Export-Tool#keeping-a-project-in-git-from-the-ide) uses this command to open a fresh clone. +If the folder holds the compiler packages under `Packages`, as an export by the IDE does, delete their folders first: imported with them, the project gets a copy of them that the compiler does not use. See [Packing the export back into a project](../Projects/Saving-and-Exporting#packing-the-export-back-into-a-project). [Keeping a project in Git from the IDE](../../../Features/Packages/Import-Export-Tool#keeping-a-project-in-git-from-the-ide) uses this command to open a fresh clone. ## Samples diff --git a/docs/IDE/Project Explorer.md b/docs/IDE/Project Explorer.md deleted file mode 100644 index 685e9caf..00000000 --- a/docs/IDE/Project Explorer.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: Project Explorer -parent: IDE -# nav_order: 2 -permalink: /tB/IDE/Project/Explorer ---- - -# Project Explorer - -![The PROJECT EXPLORER panel with no project open: its title bar carries only a drag grip and a close button, and the body below it is empty.](Images/ProjectExplorer.png){:width="400" height="116"} - -![The same panel with SampleProject loaded, its root node expanded over six yellow folders, each with a plus box for expanding it: ImportedTypeLibraries, Miscellaneous, Packages, References, Resources and Sources, the last of them selected.](Images/ProjectExplorer_Sample.png){:width="400" height="200"} - -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} ImportedTypeLibraries -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} Miscellaneous -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} Packages -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} References -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} Resources -![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} Sources - -When a Project is open contextual icons will appear. - -![The PROJECT EXPLORER title bar once a project is open, with four buttons at its right: a settings gear, a toggle file view icon of two overlapping documents, a plus for adding items, and the panel close button.](Images/ProjectExplorer_Header.png){:width="400" height="30"} - -## ![](Images/Settings.png){:width="16" height="16"} Project Settings - -- [Info](../Project-Settings) - -## ![](Images/Toggle.png){:width="16" height="16"} Toggle file view (Ctrl+R) - - -## ![](Images/Add.png){:width="16" height="16"} Add... - -Same as Right-Click - -## Right-Click - Add - -![The Project Explorer context menu with its Add submenu open alongside it. The submenu runs from Add Folder through the Windows Form, MDI Form, UserControl, PropertyPage and Report entries, the CustomControls form, the .TWIN module and class, the .BAS module and .CLS class, Add Other File, Import, and three Add Resource lines. The menu beside it lists Add, Cut, Copy, Paste, Copy Name, Copy Path, View As JSON, View As Markdown Preview, Rename, Export and Delete Permanently, with Cut, Copy, Paste and the two View As entries greyed out.](Images/RightClick-Add.png){:width="510" height="492"} - -- ![](Images/Folder.png){:width="16" height="11"} Add Folder -- ![](Images/tB-Green.png){:width="16" height="16"} Add Windows Form -- ![](Images/tB-Green.png){:width="16" height="16"} Add Windows MDI Form -- ![](Images/tB-Green.png){:width="16" height="16"} Add Windows UserControl -- ![](Images/tB-Green.png){:width="16" height="16"} Add Windows PropertyPage -- ![](Images/tB-Green.png){:width="16" height="16"} Add Windows Report - ---- - -- ![](Images/tB-Green.png){:width="16" height="16"} Add CustomControls Form - ---- - -- ![](Images/tB-Red.png){:width="16" height="16"} Add Module (.TWIN supporting Unicode) -- ![](Images/tB-Red.png){:width="16" height="16"} Add Class (.TWIN supporting Unicode) - ---- - -- ![](Images/tB-Blue.png){:width="16" height="16"} Add Module (.BAS) -- ![](Images/tB-Orange.png){:width="16" height="16"} Add Class (.CLS) - ---- - -- ![](Images/File-Green.png){:width="16" height="16"} Add Other File - ---- - -- ![](Images/File-Green.png){:width="16" height="16"} Import - ---- - -- Add Resource: Visual Styles Manifest -- Add Resource: String Table -- Add Resource: MESSAGETABLE - -## ![](Images/Folder.png){:width="16" height="11"} Folder -{: #folder } - -## ![](Images/tB-Green.png){:width="16" height="16"} Windows Form -{: #windows-form } - -The form designer opens on the new file. See [Add a form](../Forms/Designer#add-a-form). - -## ![](Images/tB-Green.png){:width="16" height="16"} Windows MDI Form -{: #windows-mdi-form } - -## ![](Images/tB-Green.png){:width="16" height="16"} Windows UserControl -{: #windows-usercontrol } - -## ![](Images/tB-Green.png){:width="16" height="16"} Windows PropertyPage -{: #windows-propertypage } - -## ![](Images/tB-Green.png){:width="16" height="16"} Windows Report -{: #windows-report } - -The report designer opens on the new file. See [Designing reports](../Reports/). - -## ![](Images/tB-Green.png){:width="16" height="16"} CustomControls Forms -{: #customcontrols-forms } - -![A twinBASIC message box headed Package needed: CustomControls, saying that a reference to the CustomControls package must be added to the project first and that the compiler will be restarted once it is, above an Add CustomControls package button and a Cancel button.](Images/RightClick-Add-CustomControlsForm-Popup.png){:width="539" height="194"} - -## ![](Images/tB-Red.png){:width="16" height="16"} Module -{: #module } - -## ![](Images/tB-Red.png){:width="16" height="16"} Class -{: #class } - -## ![](Images/File-Green.png){:width="16" height="16"} Other File -{: #other-file } - -## ![](Images/File-Green.png){:width="16" height="16"} Import -{: #import } - -## Resource: Visual Styles Manifest -{: index="visual styles" } - -An application manifest is an XML file that Windows reads when it starts the program. The one this command adds declares a dependency on version 6 of the Windows Common Controls, so that the program's buttons, lists and other controls are drawn in the current Windows visual style rather than the classic one. It is stored as resource `#1` in the project's `MANIFEST` resource folder, and the build embeds it in the program. - -A manifest can also declare the program's DPI awareness. A program whose manifest does should set [Force DPI Awareness At Startup](../Project-Settings#dpi-awareness) to **NONE**. - -See ![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} `/.../Resources/MANIFEST/#1.xml` - -```xml - - - - Application description here - - - - - - -``` - -## Resource: String Table - -See ![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} `/.../Resources/STRING/Strings.json` - -```json -[ - { - "id": 101, - "name": "MyLocalizedString1", - "LCID_0000": "This is my NEUTRAL text for MyLocalizedString1", - "LCID_0409": "This is my USA text for MyLocalizedString1", - "LCID_0407": "This is my GERMAN text for MyLocalizedString1", - "LCID_0809": "This is my UK text for MyLocalizedString1" - }, - { - "id": 102, - "name": "MyLocalizedString2", - "LCID_0000": "This is my NEUTRAL text for MyLocalizedString2", - "LCID_0409": "This is my USA text for MyLocalizedString2", - "LCID_0407": "This is my GERMAN text for MyLocalizedString2", - "LCID_0809": "This is my UK text for MyLocalizedString2" - } -] -``` - -## Resource: MESSAGETABLE - -See ![A small yellow folder icon](Images/Folder.png){:width="16" height="11"} `/.../Resources/MESSAGETABLE/Strings.json` - -```json -{ - "events": - [ - { - "id": -1073610751, - "name": "service_started", - "LCID_0000": "%1 service started" - }, - { - "id": -1073610750, - "name": "service_startup_failed", - "LCID_0000": "%1 service startup failed" - }, - { - "id": -1073610749, - "name": "service_ended", - "LCID_0000": "%1 service ended" - }, - { - "id": -1073610748, - "name": "service_stopping", - "LCID_0000": "%1 service stopping" - } - ], - "categories": - [ - { - "id": 1, - "name": "status_changed", - "LCID_0000": "Status Changed" - } - ] -} -``` diff --git a/docs/IDE/Project Settings.md b/docs/IDE/Project Settings.md index 7492ea74..f6230531 100644 --- a/docs/IDE/Project Settings.md +++ b/docs/IDE/Project Settings.md @@ -13,7 +13,7 @@ The Project Settings dialog, **Project → Project Settings...**, holds the sett ![The Option Explicit On setting in the Project Settings dialog, set to Yes, with an arrow pointing at the description under it](Images/project settings description text.png){:width="900" height="67"} -The drop-down list of a setting ends with a **COMPILER DEFAULT** entry, which names the value used when the project does not set one. Choosing it removes the setting from the project's `Settings` file, and so does emptying a box. [**File → Export Project**](Reference/Menu/File#export-project) writes that file beside the project's `Sources` folder, and the entries below give the settings' keys in it. +The drop-down list of a setting ends with a **COMPILER DEFAULT** entry, which names the value used when the project does not set one. Choosing it removes the setting from the project's `Settings` file, and so does emptying a box. [**File → Export Project**](Projects/Saving-and-Exporting#export-project) writes that file beside the project's `Sources` folder, and the entries below give the settings' keys in it. {: .toc } @@ -52,7 +52,7 @@ To add a reference, tick it on the **Available COM References** tab, which lists ![The same dialog on its Available COM References tab. A search box sits above an alphabetical list of unticked type libraries registered on the machine --- on this machine ABBYY FineReader 16 SharePoint Integration Component, AccessibilityCplAdmin, Acrobat, Acrobat Access and so on --- against Library Symbol, Version and Publisher columns.](Images/ProjectSettings_AvailableCOMReferences.png){:width="1102" height="774"} -See [Packages](../../Features/Packages/) +See [Packages](../../Features/Packages/). [References and packages](Projects/References-and-Packages) describes the three lists, the questions the IDE asks, and closing the dialog. ![The Project Settings dialog open over the IDE, with red numbers marking the route: 1 on the Project Explorer's Project Settings gear, 2 on the Library References heading, 3 on the Available Packages tab. That tab lists the built-in and published packages with tick boxes and Embedded and Library Symbol columns.](../Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png){:width="1162" height="529"} @@ -278,7 +278,7 @@ When set to **Yes**, the build marks the file as DEP-aware. On hardware that sup ## Export > [!WARNING] -> **File → Export Project** deletes everything in its target folder before it writes, without asking. Read [Export Project](Reference/Menu/File#export-project) before setting these. +> **File → Export Project** deletes everything in its target folder before it writes, without asking. Read [Export Project](Projects/Saving-and-Exporting#export-project) before setting these. ### Export Path diff --git a/docs/IDE/Projects/Adding-Files.md b/docs/IDE/Projects/Adding-Files.md new file mode 100644 index 00000000..9b637ede --- /dev/null +++ b/docs/IDE/Projects/Adding-Files.md @@ -0,0 +1,258 @@ +--- +title: Adding files +parent: Projects and files +grand_parent: IDE +nav_order: 3 +permalink: /tB/IDE/Projects/Adding-Files +index: + - add a module + - add a class + - import a file + - resources + - string table + - manifest +--- + +# Adding files + +The **Add** menu makes new files and folders in the project, imports files from disk, and adds the three kinds of resource that the IDE has templates for. This page describes the menu, how a new file is named and placed, what each template holds, how **Import** works, and how resources are managed. + +## The Add menu + +The **Add** menu opens in three ways, and the three lists are the same. + +- Right-click a row of the **PROJECT EXPLORER** and choose **Add**. The submenu opens when you point at the item. +- Choose the **Add...** button in the title bar of the panel. +- Choose **Project → Add**. + +![The Project Explorer's right-click menu on the Sources folder, with the Add submenu open beside it. The submenu runs from folders and forms through modules and classes to Import and the three resources. Cut, Copy, Paste and both View As entries of the main menu are greyed out.](../Images/RightClick-Add.png){:width="510" height="492"} + +Choosing an item from the object view switches the panel to the file view first, because the new file appears in the tree. + +| Item | Creates | The name box starts with | +|---|---|---| +| **Add Folder** | A folder. | `MyFolder` | +| **Add Windows Form**, **Add Windows MDI Form**, **Add Windows UserControl**, **Add Windows PropertyPage**, **Add Windows Report**, **Add CustomControls Form**, and **Add** *name* **Form** for each kind of form that a package supplies | A designer file and a `.twin` file with the same name. [Designer](../Forms/Designer#add-a-form) describes them, and [Designing reports](../Reports/) the report. | `MyForm`, `MyUserControl`, `MyPropertyPage` or `MyReport` | +| **Add Module (.TWIN supporting Unicode)** | `MyModule.twin`, a module in a file that can hold any Unicode text. | `MyModule` | +| **Add Class (.TWIN supporting Unicode)** | `MyClass.twin`, a class in a file that can hold any Unicode text. | `MyClass` | +| **Add Module (.BAS)** | `MyModule.bas`, a module in the VB6 file format. | `MyModule` | +| **Add Class (.CLS)** | `MyClass.cls`, a class in the VB6 file format. | `MyClass` | +| **Add Other File** | An empty file, with the name you type. | `MyFile`, with no extension | +| **Import...** | Files copied from disk. See [Import](#import). | | +| **Add Resource: Visual Styles Manifest**, **Add Resource: String Table**, **Add Resource: MESSAGETABLE** | A resource file. See [Resources](#resources). | None: no name box opens | + +The items for the Windows forms and for the CustomControls form are always listed, whether or not the project refers to the package they need. If it does not, a box asks to add the package first. See [Package needed](References-and-Packages#package-needed). + +## Name the new file + +Choosing an item that makes a file opens a name box in the tree, in the row where the file will appear. It holds the default name with the name part selected, such as `MyModule.twin` with `MyModule` selected. + +![The Project Explorer in its file view with the Sources folder expanded. The first row under Sources is a name box holding MyForm.tbform, with MyForm selected; the project's own files follow it.](../Forms/Images/Designer_AddName.png){:width="267" height="304"} + +- Type a name and press Enter to create the file. Esc, or an empty box, creates nothing. +- You can type the extension or leave it out. A trailing `.twin`, `.bas` or `.cls` is cut off, and the extension of the item is used. +- If the default name is taken, the box offers `MyModule2.twin`, `MyModule3.twin` and so on. The count is for the folder the file goes into. +- The new file opens at once in a normal tab, not a preview tab. + +A name is refused when it is empty, begins with a period, contains one of `\ / : * ? " < > |`, or is the name of a file or folder already in the folder. The box turns red while you type such a name, and Enter creates nothing and shows the notification **Cannot create: the new name entered is invalid.** The name is compared with its extension, so `Legacy.twin` can sit beside `Legacy.bas`. + +A name that contains a space is written in square brackets in a `.twin` file, as `Module [My Module]`. In a `.bas` or `.cls` file it goes unchanged into the `Attribute VB_Name` line. + +### Where the new file goes + +The new file goes into the selected folder, or into the folder of the selected file. A folder that is collapsed opens. Two cases differ: + +- A file of a code kind, which means a `.twin`, `.bas` or `.cls` file or a designer file, goes into `Sources` if the selection is not inside `Sources`. That includes a selection in `Resources`, and the project's own row. +- With nothing selected, a new file or folder goes into `Sources`. + +**Add Folder** and **Add Other File** are not moved to `Sources`: a file made with **Add Other File** while a file in `Resources/CUSTOM` is selected is made in `Resources/CUSTOM`. + +> [!NOTE] +> In twinBASIC BETA 1005, **Add Other File**, and **Paste**, in the `Packages` folder create nothing. The notification says *cannot create files inside the root resources folder*, which names the wrong folder. A file that was cut and then pasted there is deleted: see [Cut, copy and paste](Files-and-Folders#cut-copy-and-paste). + +## What the new files hold + +A `.twin` module or class holds a few lines: + +```tb +Module MyModule + + ' add your procedures here + +End Module +``` + +```tb +Class MyClass + + ' add your member fields and procedures here + +End Class +``` + +A `.bas` module holds `Attribute VB_Name = "MyModule"` and a comment line. A `.cls` class holds the header of a VB6 class module, the properties `MultiUse`, `Persistable`, `DataBindingBehavior`, `DataSourceBehavior` and `MTSTransactionMode`, and `Attribute VB_Name = "MyClass"`, with the attributes `VB_GlobalNameSpace`, `VB_Creatable`, `VB_PredeclaredId` and `VB_Exposed`, then a comment line. + +The `.twin` files are written as UTF-8 with Windows line endings. The `.bas` and `.cls` files are written in the ANSI code page of Windows, and so can hold only the characters of that code page. **Add Other File** creates an empty file. + +## Import + +**Import...** opens the Windows **Open** dialog. It accepts several files at once. What the IDE does with each file depends on its extension. + +### Ordinary files + +A file with any extension but the three below is copied into the project unchanged. It goes into the selected folder, or the folder of the selected file, or `Sources` if nothing is selected. The IDE does not ask when a file of the same name is there already: the new file replaces it. + +> [!WARNING] +> In twinBASIC BETA 1005, importing a file with the name of a file already in the project crashes the compiler, whether or not the file is open. The Debug Console prints `NATIVE EXCEPTION: ACCESS_VIOLATION`, and the IDE restarts the compiler. When the file is open in a tab, the project then holds the imported text, but the tab keeps the old text. If you edit the tab and press Ctrl+S, the old text with your edit is saved over the import. Close the tab of a file before you import a file with its name. + +### Projects and packages + +A file with the extension `.twinproj`, `.twinpack` or `.vbp` is not copied. The IDE reads it and opens the dialog **Import from twinproj...**, which lists what the file holds, as a tree with a check box on every entry. A VB6 project is listed with its files already converted: `Form1.frm.tbform` and `Form1.frm.twin` for a form. Tick both. + +![The Import from twinproj dialog. A tick-box tree lists everything found in a VB6 project, with a Resources branch open over its ICON and MANIFEST folders and a Sources branch below. The two files of a form are both ticked.](../../Miscellaneous/Images/16833fae-4bd7-418f-bb16-691a611a5b01.png){:width="468" height="397"} + +The tree shows the project's folders and files but not its `Packages`, `Settings`, `References` and `ImportedTypeLibraries` entries, and not the `.meta` file. Ticking a folder ticks everything in it. Ticking a file leaves its folders part-ticked. The **Import** button is hidden until something is ticked. Click the box of a row, or double-click the row, to tick it. + +**Import** writes each ticked file at the same path in the current project, and makes the folders for it. A file already at that path is replaced with no question. If the import fails, a box says **Import failed. Please check the DEBUG CONSOLE for details of the errors that occurred.** + +> [!WARNING] +> In twinBASIC BETA 1005, importing a project's files replaces a file of the same path without a question, and closes the tab open on it first. Unsaved changes in that tab are lost, and so is the saved copy of the file, because the import also saves the project. Do not tick a file whose path is already in your project. + +This is for taking files from another project. To open a whole VB6 project as a new twinBASIC project, use **File → Open Project...** on its `.vbp`, or the **Import from VBP...** and **Import from folder...** tiles of the [New Project](../Project/New) dialog. The [FAQ](../../../FAQ#vb6-import) describes the VB6 import. A package is added as a package in [Project Settings](References-and-Packages#available-packages), not here. + +### The project is saved + +When every file of the command is done, the IDE saves the project, as if you had pressed Ctrl+S. For a project with no file yet, the **Save As** dialog opens instead. Cancelling it leaves the file imported and the project unsaved. + +> [!NOTE] +> In twinBASIC BETA 1005, an import saves the project, with the unsaved changes of every open editor, although you did not ask for a save. **Cancel** in the **Import from twinproj...** dialog does the same, and then the IDE restarts its compiler. +## Resources + +A resource is a file that the build embeds in the program, such as an icon, a bitmap, a manifest or a table of strings. The resources are in the `Resources` folder, in a subfolder named for the resource's type. A new Standard EXE project has `Resources/ICON/twinBASIC.ico`. A project that uses Visual Styles also has a `MANIFEST` folder. The `STRING` and `MESSAGETABLE` folders appear when you add those resources. + +![The right of the IDE window: the title bar, the toolbar, the editor and the Project Explorer. In the tree the Resources branch is open over an ICON folder, a MANIFEST folder and the folders MESSAGETABLE and STRING, above the Sources branch.](../../Miscellaneous/Images/71ddde83-a091-47e3-b5b8-681954b0639d.png){:width="940" height="426"} + +The IDE has no resource editors. An icon, a bitmap, a cursor, another image or a PDF opens in a read-only [preview tab](Project-Explorer#what-a-click-opens), and every other resource opens as text. The version information of the program is not a file: it is the **VERSION Resource** section of [Project Settings](../Project-Settings#version-resource). + +![The Project Explorer's ICON folder open to two entries, MyOwnIcon.ico above twinBASIC.ico, beside the Toolbox and a form open in the designer.](../../Miscellaneous/Images/8611d12a-d7a6-48cc-9544-cb27c5299aa5.png){:width="642" height="461"} + + + +The compiler decides which folder names are resource types. The [FAQ](../../../FAQ#resources) lists them. To add a resource of another type, make a folder with its name under `Resources`: choose **Add Folder** with `Resources` selected. Then select the new folder and use **Import...**. A file that is imported over a resource of the same name replaces it. + +The [FAQ](../../../FAQ#app-icon) describes how the program gets its icon, from the [Icon Form](../Project-Settings#icon-form) setting or from `Resources/ICON`. + +### The three resource items + +**Add Resource: Visual Styles Manifest**, **Add Resource: String Table** and **Add Resource: MESSAGETABLE** each write one file into `Resources`, make its folder if it is missing, and open it in a tab. They ignore what is selected, and they ask for no name. The files are written with Unix line endings. + +If the file exists already, a box says **File already exists:** and gives the path. **Replace it** writes the template over the file and selects its tab. **Cancel** selects the tab of the existing file. + + + +### Visual Styles Manifest +{: index="visual styles" } + +An application manifest is an XML file that Windows reads when it starts the program. The one this command adds declares a dependency on version 6 of the Windows Common Controls, so that the program's buttons, lists and other controls are drawn in the current Windows visual style rather than the classic one. It is stored as resource `#1` in the project's `MANIFEST` resource folder, and the build embeds it in the program. + +The file is `Resources/MANIFEST/#1.xml`. + +```xml + + + + Application description here + + + + + + +``` + +### String Table + +A string table holds named strings, each with a text for every language. The IDE edits it as JSON. The file is `Resources/STRING/Strings.json`, and the template holds two example strings. + +![An editor tab holding Strings.json, a JSON array of two entries, each with an id, a name and one line per locale, keyed LCID_0000 for the neutral text through LCID_0809. The Project Explorer beside it shows the file inside a STRING folder under Resources.](../../Miscellaneous/Images/97cc8655-7a8b-47f3-b52c-eb1ddfce662f.png){:width="1040" height="417"} + +```json +[ + { + "id": 101, + "name": "MyLocalizedString1", + "LCID_0000": "This is my NEUTRAL text for MyLocalizedString1", + "LCID_0409": "This is my USA text for MyLocalizedString1", + "LCID_0407": "This is my GERMAN text for MyLocalizedString1", + "LCID_0809": "This is my UK text for MyLocalizedString1" + }, + { + "id": 102, + "name": "MyLocalizedString2", + "LCID_0000": "This is my NEUTRAL text for MyLocalizedString2", + "LCID_0409": "This is my USA text for MyLocalizedString2", + "LCID_0407": "This is my GERMAN text for MyLocalizedString2", + "LCID_0809": "This is my UK text for MyLocalizedString2" + } +] +``` + +### MESSAGETABLE + +A message table holds events and categories, each with an identifier, a name and a text. The file is `Resources/MESSAGETABLE/Strings.json`, and the template holds four events of a service and one category. + +```json +{ + "events": + [ + { + "id": -1073610751, + "name": "service_started", + "LCID_0000": "%1 service started" + }, + { + "id": -1073610750, + "name": "service_startup_failed", + "LCID_0000": "%1 service startup failed" + }, + { + "id": -1073610749, + "name": "service_ended", + "LCID_0000": "%1 service ended" + }, + { + "id": -1073610748, + "name": "service_stopping", + "LCID_0000": "%1 service stopping" + } + ], + "categories": + [ + { + "id": 1, + "name": "status_changed", + "LCID_0000": "Status Changed" + } + ] +} +``` + +## See Also + +- [Project Explorer](Project-Explorer) -- the tree where the new files appear +- [Files and folders](Files-and-Folders) -- rename, move, copy and delete +- [References and packages](References-and-Packages) -- adding a library or a package to the project +- [Designer](../Forms/Designer#add-a-form) -- the form, user control and property page items +- [Project menu](../Reference/Menu/Project) -- the menu that has **Add** diff --git a/docs/IDE/Projects/Files-and-Folders.md b/docs/IDE/Projects/Files-and-Folders.md new file mode 100644 index 00000000..fe42cacf --- /dev/null +++ b/docs/IDE/Projects/Files-and-Folders.md @@ -0,0 +1,170 @@ +--- +title: Files and folders +parent: Projects and files +grand_parent: IDE +nav_order: 2 +permalink: /tB/IDE/Projects/Files-and-Folders +index: + - rename a file + - delete a file + - move a file + - copy a file + - view as json +--- + +# Files and folders + +The right-click menu of the **PROJECT EXPLORER** holds the commands that change the files of a project. This page describes the menu, and then each command in turn: renaming, moving, copying, exporting and deleting. [Adding files](Adding-Files) describes the **Add** item. + +The commands that change files change the project in memory. Nothing reaches the `.twinproj` file until the project is [saved](Saving-and-Exporting#save-project), by you or, in a few cases, by the IDE itself (see [Other commands that save](Saving-and-Exporting#other-commands-that-save)). None of the commands can be undone. + +## The right-click menu + +A right click on a row opens the menu for the rows selected. A right click on a row that is not selected selects it first. A right click on the empty space below the tree opens the menu with nothing selected, and then only **Add** and **Export...** are available. + + + +An item that does not apply is greyed out, not hidden. The keys work when the tree has the focus in the file view. + +**Add** +: Opens a submenu of the things that can be added. See [Adding files](Adding-Files). + +**Cut** (Ctrl+X, Shift+Delete), **Copy** (Ctrl+C, Ctrl+Insert) and **Paste** (Ctrl+V) +: Move or copy files inside the project. They work on files only. **Cut** is greyed out when a folder or a read-only row is selected, and **Paste** when the clipboard holds nothing the IDE put there. See [Cut, copy and paste](#cut-copy-and-paste). + +**Copy Name** and **Copy Path** +: Put the names, or the IDE paths, of the selected rows on the clipboard as text. Several are joined with a semicolon. A path is written as `//Sources/Startup.twin`. It is the IDE's path, not a path on disk. + +**View As JSON** and **View As Markdown Preview** +: Open a read-only copy of a file in a tab, as JSON text or as a rendered Markdown preview. See [View as JSON](#view-as-json-and-markdown-preview). + +**Rename** (F2) +: Changes the name of a file, folder or the project. See [Rename](#rename). + +**Export...** +: Writes the selected rows to a folder on disk. See [Export a file](#export-a-file). + +**Delete Permanently** (Delete) +: Removes the selected rows from the project. See [Delete](#delete). + +**Cut**, **Rename** and **Delete Permanently** are greyed out when any selected row is read-only, as the files of a package are. The menu has no item that duplicates a file, and none that opens a file's folder in Windows Explorer. **Project → Open Project Folder...** opens the folder of the `.twinproj` file. + +## Rename + +Select a row and press F2, or choose **Rename**. A text box replaces the name in the row, with the name selected up to the last period, or all of it for a name with none. Typing checks the name at every key, and the box turns red when the name is not allowed. Enter, or a click anywhere else, renames the file. Esc leaves the name as it was. + + + +A name is refused, with a notification in the corner of the window, when it: + +- is empty, or begins with a period, or ends with a period or a space; +- contains any of `\ / : * ? " < >` or `|`; +- is the same as the current name, or differs from it only in case; +- is the name of another entry in the same folder, in any case. + +The notification reads **Cannot rename: the new name entered is invalid.** The seven special folders, `Settings`, `Sources`, `Resources`, `References`, `Packages`, `Miscellaneous` and `ImportedTypeLibraries`, cannot be renamed at all: the notification is **Cannot rename: permission denied.** + +> [!NOTE] +> In twinBASIC BETA 1005, a rename that changes only the case of a name, or nothing, is refused with the same message as an invalid name, so `legacy.bas` cannot be changed to `Legacy.bas` in the tree. + +If the file is open in a tab with changes you have not saved, the IDE refuses the rename and shows a box, **Rename/Move failed. Please close the following editors that are preventing the operation:**, with the paths of the files. The same box appears for a folder that holds such a file. Save the file, or close its tab, and rename again. A tab on a file with no unsaved changes does not stop the rename. The tab closes, and the IDE does not open it again under the new name. Bookmarks move with the file. + +### A form and its code + +A form's designer file and its `.twin` file belong together. After you rename one, the IDE shows a notification, **Rename** *the partner* **to** *the new name* **also?**, with **YES** and **NO** buttons. **YES** renames the partner as well. **NO** leaves it. The question comes whichever of the two you rename. It does not come when the base names of the two files already differ. The class named inside the `.twin` file does not change either way: edit it in the code. + + + +### The project + +The top row of the tree is the project. Renaming it changes the **Project Name** setting in the `Settings` file. The row, the title bar and the `.twinproj` file keep their names. A name that is not a valid project name gives **Cannot rename the project: the new name entered is invalid.** + +> [!NOTE] +> In twinBASIC BETA 1005, renaming the project also saves it, with the unsaved edits of the open editors, and the title bar's changed mark goes. + +## Move a file or folder by dragging + +Drag a row, or the selected rows, onto a folder. The folder under the pointer is highlighted while you drag. The rows move into the folder at once. The IDE does not ask, and the move cannot be undone. A drop on a file, or on the row itself, does nothing. + +- A form's designer file moves without its `.twin` file, and the other way round, unless both are selected. +- A file with unsaved changes in an open tab is not moved. The box **Rename/Move failed** appears, as it does for a rename. +- The `Resources` folder accepts a dropped file, although **Paste** refuses to put one there. +- A file dragged in from Windows is not accepted. + +> [!WARNING] +> In twinBASIC BETA 1005, dragging a folder onto one of its own files, or onto one of its own subfolders, is accepted with no message. The tree then nests the folder inside itself, about fifty levels deep. The next Ctrl+S prints the green `[DONE]` line in the Debug Console, and then an error, and it writes a project file that the IDE cannot open: opening it stops at *Please wait... 25.0%*. Never drop a folder onto anything inside it. If you did, do not save. Close the project with **Discard Changes** in the question that follows, and open it again. + +> [!NOTE] +> In twinBASIC BETA 1005, nothing stops a drag of a special folder. Dragging `Sources` onto `Miscellaneous` moves it there with no message, and the next save keeps it there. Do not drag the special folders. A drop of a file on `Packages` does nothing. + +## Cut, copy and paste + +**Copy** and **Cut** put the paths of the selected files on the clipboard in a format only the IDE reads. **Paste** puts the files into the selected folder, or into the folder of the selected file. A file cannot be pasted into another program, and a file copied in Windows cannot be pasted into the project: use [Import](Adding-Files#import) for that. Plain text on the clipboard gives the notification **bad clipboard data**. + +- A name that already exists in the folder gets a suffix: `Startup.twin` pastes as `Startup copy.twin`, then `Startup copy 2.twin`, and so on. +- **Cut** and **Paste** make a copy and delete the original. A cut file pasted into its own folder stays where it is. +- Only the selected files are pasted. To copy a form, select its designer file and its `.twin` file both. +- The menu greys out **Cut** for a read-only row, such as a file of a package. Ctrl+X on a `References` entry still puts a cut on the clipboard. +- The menu greys out **Cut** and **Copy** for a folder. Ctrl+C on a folder still puts its path on the clipboard. + +> [!WARNING] +> In twinBASIC BETA 1005, a file that you cut and paste onto the `Resources` folder itself, or onto `Packages`, is deleted. The IDE shows the notification *cannot create files inside the root resources folder*, which does not say so. The file is gone from the whole tree, and the next save writes the project without it. Do not cut a file into either folder. If a file went, close the project with **Discard Changes** before you save, and the saved project still has it. + +> [!NOTE] +> In twinBASIC BETA 1005, pasting a file with no extension into a folder whose own name contains a period, such as `v1.2`, creates nothing and gives no message, when a file of that name is in the folder already. The IDE takes the file's extension from the last period of the whole path. + +## Export a file + +**Export...** writes the selected files and folders to a folder on disk, as ordinary files. It opens the Windows **Browse For Folder** dialog, headed **WARNING: This will overwrite any existing files!** and **Export 1 item to:** or, for more rows, **Export 2 items to:** and so on, and starting in the folder of the project. The files go into the folder you choose. + +- A file is written under its own name. A file already there is overwritten, with no question. +- A folder is written with its subfolders. `Resources/ICON` is written as `ICON\AppIcon.ico`, for example. +- A designer file is written alone: its `.twin` file goes only if you select it too. + +The Debug Console prints `[EXPORT] DONE:` and the full path for each file. If the export fails, a box reads **ERROR: exportFile failed. Error code** and a number. + +This command exports the rows you select. **File → Export Project** exports the whole project, and it empties its folder first; see [Export Project](Saving-and-Exporting#export-project). + +## View as JSON and Markdown preview + +**View As JSON** opens a file as text in a read-only tab, titled `JSON: 'frmMain.tbform':`. It is available for the four kinds of designer file, `.tbform`, `.tbcontrol`, `.tbppage` and `.tbreport`, and for the rows directly under `Packages`. It is greyed out for other files, and for a designer file selected together with other rows. + +The first lines of the tab are a comment that gives the `URI:` of the file and the `SNAPSHOT:` time. The tab is a copy as it was when you chose the command, and it does not follow later changes. It does include the changes that are open in the designer and not yet saved. A second **View As JSON** on the same file opens a second tab of the same name. + +![The Project Explorer with the Packages folder open and the right-click menu of a package, with View As JSON highlighted.](../../Features/Images/22660f54-ff5d-4b21-93d3-39715f1f35ed.png){:width="485" height="409"} + +![A package shown as JSON in the editor, listing its components with their events, fields and procedures.](../../Features/Images/a6525b1d-ac22-4303-ae27-7984c20eba0c.png){:width="756" height="198"} + +**View As Markdown Preview** is available for a `.md` file. It opens the formatted text in a read-only tab titled `MD: 'Notes.md':`, which is a copy as it was when you chose the command. + +## Delete + +Select the rows, and press Delete or choose **Delete Permanently**. The IDE removes the rows from the project. Nothing goes to the Recycle Bin, because the files never existed on disk. The tabs open on a deleted file, or on a file in a deleted folder, are closed. + +When **File Explorer: Ask Before Delete Files** is on, which is the default, a box asks first. [IDE Options](../Customising/IDE-Options#project-explorer-tabs-and-start-up) describes the option. The box depends on the selection, and each says that you will not be able to undo the operation. + +- For one row: **Are you sure you want to delete** *the path*, with **Delete** and **Cancel**. +- For one row that has a partner, a designer file or its `.twin` file: the two paths, with **Delete Both**, **Delete** *the file's name*, and **Cancel**. The second button deletes only the file you selected. +- For several rows: **Are you sure you want to delete the selected items?**, with **Delete** and **Cancel**. + + + +With the option off, the rows are deleted at once. + +Some folders cannot be deleted. For `Sources`, `References`, `Miscellaneous`, `ImportedTypeLibraries` and the compiler packages under `Packages`, the box is shown, but nothing is deleted and no message follows. + +> [!WARNING] +> In twinBASIC BETA 1005, a file with unsaved changes in an open tab is deleted without a word about the changes. The box is the plain one, the tab closes, and the changes go with the file. A folder that holds such a file is the same. Look for the dot on a tab before you delete its file. The saved copy stays in the `.twinproj` file until the next save, so closing the project with **Discard Changes** brings the file back. + +> [!WARNING] +> In twinBASIC BETA 1005, deleting the project's own row, the top row of the tree, deletes every file in the project. The box reads like a file's: *Are you sure you want to delete* the project's path. After you confirm, the tree is empty, and the only message is an *IDE internal error* line in the Debug Console. The next Ctrl+S prints the green `[DONE]` line and writes a project with no files over the project file. Never delete the top row. If you did, do not save: close the project with **Discard Changes** and open it again. + +> [!NOTE] +> In twinBASIC BETA 1005, Delete with nothing selected shows the box **Are you sure you want to delete the selected items?**, and deletes nothing. Choose **Cancel**. Deleting an entry under `References` removes its row from the tree, but not the reference: it stays in the project's settings. Remove a reference in [Project Settings](References-and-Packages#the-enabled-libraries-list). + +## See Also + +- [Project Explorer](Project-Explorer) -- the tree, its views and what a click opens +- [Adding files](Adding-Files) -- new files, imports and resources +- [Saving and exporting](Saving-and-Exporting) -- writing the project to disk +- [Navigating](../Code/Navigating) -- **OPEN EDITORS** and **HISTORY**, for the files you have open diff --git a/docs/IDE/Projects/Project-Explorer.md b/docs/IDE/Projects/Project-Explorer.md new file mode 100644 index 00000000..318ea3fa --- /dev/null +++ b/docs/IDE/Projects/Project-Explorer.md @@ -0,0 +1,163 @@ +--- +title: Project Explorer +parent: Projects and files +grand_parent: IDE +nav_order: 1 +permalink: /tB/IDE/Projects/Project-Explorer +redirect_from: + - /tB/IDE/Project/Explorer +index: + - project explorer + - file view + - object view + - toggle file view +--- + +# Project Explorer + +The **PROJECT EXPLORER** panel shows the files of the open project as a tree, or the objects of the project as a list. This page describes the panel, its two views and what a click on a file opens. [Files and folders](Files-and-Folders) describes the right-click menu and the commands that change files. + +![The PROJECT EXPLORER panel with no project open. Its title bar has only a drag grip and a close button, and the body below it is empty.](../Images/ProjectExplorer.png){:width="400" height="116"} + +With no project open the panel is empty. When a project is open, the tree shows the project's name with its folders below it. + +![The same panel with a sample project loaded. The project's name is expanded over six yellow folders, each with a plus box for expanding it. The last one, Sources, is selected.](../Images/ProjectExplorer_Sample.png){:width="400" height="200"} + +## The header buttons + +Four buttons sit in the title bar once a project is open. + +![The PROJECT EXPLORER title bar with a project open. Four buttons are at the right: a gear, an icon of two overlapping documents, a plus sign, and the panel's close button.](../Images/ProjectExplorer_Header.png){:width="400" height="30"} + +**Project Settings** +: Opens the [Project Settings](../Project-Settings) dialog. **Project → Project Settings...** does the same. + +**Search** +: Opens the search bar of the [object view](#the-object-view). The button shows only in the object view. + +**Toggle file view** (Ctrl+R) +: Switches between the file view and the object view. + +**Add...** +: Opens the **Add** menu below the button. It lists the same items as the **Add** entry of the right-click menu, and [Adding files](Adding-Files) describes them. + +A button whose command does not apply is hidden, not greyed out. Hovering over a button shows its key in its title. + +## The two views + +The **file view** is the tree of the project's files and folders. The **object view** is a flat list of the project's modules, classes, forms and other objects, grouped by kind, with the file name beside each one. The file view is the default. + +Ctrl+R switches between them. It works whenever a project is open, whether the focus is in the panel or in the code editor. The IDE remembers the view you leave on, and opens the next session in it. + +Choosing an item of the **Add** menu from the object view switches the panel to the file view first, because the new file appears in the tree. Leaving the object view closes its search bar. + +## The file view + +Names are compared without regard to case: a folder cannot hold `Form1.twin` and `form1.twin`. An entry whose name begins with a period, such as the `.meta` file that holds the project's [saved state](Saving-and-Exporting#what-the-ide-remembers-about-a-project), is not drawn. The tree has no option to show hidden entries, and an empty folder shows the text **(empty)**. + +### The folders + +The tree draws six of the project's folders. `Settings`, the seventh, is a file that the tree does not draw; open it with the **Project Settings** button. + +- **Sources** holds the project's code and its designer files. A new file of a code kind goes into `Sources` unless a folder under `Sources` is selected. See [Adding files](Adding-Files#where-the-new-file-goes). +- **Resources** holds the files the build embeds in the program. See [Resources](Adding-Files#resources). +- **References** has one entry for each library the project refers to. See [References and packages](References-and-Packages#the-references-folder). +- **Packages** has a folder for each package the project embeds, and for the compiler packages `VB`, `VBA` and `VBRUN`. A package's files are read-only. +- **ImportedTypeLibraries** holds the type libraries that were imported from a file. See [Import from file](References-and-Packages#import-from-file). +- **Miscellaneous** is empty in a new project. + +The folders `Settings`, `Sources`, `Resources`, `References`, `Packages`, `Miscellaneous` and `ImportedTypeLibraries` cannot be renamed. The project's own name, at the top of the tree, can; [Files and folders](Files-and-Folders#rename) says how. + +### Icons and colours + +The icon of a file shows its kind. A `.twin` file has a red icon, a `.bas` file a blue one and a `.cls` file an orange one. The four kinds of designer file, `.tbform`, `.tbcontrol`, `.tbppage` and `.tbreport`, have a green one. The entries under `References`, the `Settings` file and the other files each have an icon of their own, and a folder has the folder icon. + +A file in which the compiler found an error has a light red row. Every folder above the file takes the colour as well, up to the project row, so a red folder says that something below it has an error. A file with only a warning has a yellow row. [Diagnostics](../Code/Diagnostics) lists the problems. + + + +Pointing at a row for about a second and a half shows its IDE path, such as `/MyProject/Sources/Startup.twin`. + +### Select rows + +A click selects one row. Ctrl+click adds a row to the selection, or removes it, and Shift+click selects the range from the last row you clicked. Ctrl+A selects every row shown. A right click on a row that is not selected selects it first. + +A click on the name of a folder selects it and opens or closes it. The commands that make something new, such as **Add**, put it into the selected folder, or into the folder of the selected file. + +### Keys in the tree + +These keys work while the tree has the focus. + +| Key | What it does | +|---|---| +| Up, Down | Move the selection by one row. With Shift they extend it. | +| Left | Closes an open folder. On a closed folder or a file, selects the folder above it. | +| Right | Opens a closed folder. On an open folder, selects an entry inside it. | +| Enter | On a file, opens it in a normal tab and moves the focus to the editor. On a folder, does nothing. | +| Esc | Clears the selection. | +| Ctrl+A | Selects every row shown. | +| F2, Delete, Ctrl+X, Ctrl+C, Ctrl+V | Rename, delete, cut, copy and paste. See [Files and folders](Files-and-Folders). | + +The tree scrolls to keep the selected row in view. Page Up, Page Down, Home and End do not move the selection. + +> [!NOTE] +> In twinBASIC BETA 1005, several keys of the tree do not work as they should. +> +> - Space does not open or close a folder. Click the folder's plus or minus box. +> - Typing the start of a name does not filter the tree, although the IDE has code for it. To find a file, open the folders, or switch to the [object view](#the-object-view) and search for the object by name. To find text, use [Find In Project](../Code/Finding#search-the-whole-project). +> - Right on an open folder selects the first entry in the order the compiler lists them. That is not always the first row drawn. +> - Ctrl+A selects the rows correctly, but the IDE's script also raises an error. +> - Down on the last row selects the project's `Settings` entry, which the tree does not draw, so no row is highlighted. Enter there raises an error and opens nothing. + +### What a click opens + +Whether a click opens a file depends on the option **File Explorer: Single-Click Preview**, which is off by default. With the option off, one click selects a row, and a double-click or Enter opens the file in a normal tab. With the option on, one click opens the file in a *preview tab*. [IDE Options](../Customising/IDE-Options#project-explorer-tabs-and-start-up) describes the option, and [Editor](../Code/Editor#tabs) describes preview tabs. A double-click on a folder opens or closes it. + +What opens depends on the kind of file. + +| File | What opens | +|---|---| +| `.twin`, `.bas`, `.cls` | The code editor. See [Writing code](../Code/). | +| `.tbform`, `.tbcontrol`, `.tbppage`, `.tbreport` | The designer. See [Designing forms](../Forms/Designer#open-a-designer). | +| `.ico`, `.cur`, `.png`, `.gif`, `.jpg`, `.jpeg`, `.svg`, `.bmp`, `.pdf` | A read-only preview tab that shows the file. The tab is never marked as changed. A PDF opens, but the tab shows an empty box. | +| A file with no extension in `Resources/ICON`, `Resources/BITMAP` or `Resources/CURSOR` | The same preview, as an icon, a bitmap or a cursor. | +| A Markdown file in a package | A Markdown preview. | +| An entry under `References` | The code editor, with the declarations that the compiler generates for the library. | +| Anything else, including `.json`, `.xml`, `.txt`, `.md`, and a file with no extension elsewhere | A text editor. | + +The text editor colours `.js`, `.ts`, `.html`, `.htm`, `.css`, `.json`, `.xml`, `.ini` and `.md` files by their extension, and shows any other file as plain text. It has no navigation boxes and no **OUTLINE**. A binary file opens in it too, as replacement characters, and you can type into it. + +The IDE has no resource editors. Icons, bitmaps and cursors are shown as pictures, and the manifest and the string table open as text. The version information is not a file: it is a section of [Project Settings](../Project-Settings#version-resource). + +## The object view + +The object view lists what the language server finds in the project, not the files. At the top is the project, and below it the groups, such as **Modules**, **Classes**, **Forms**, **Interfaces** and **User Defined Types**. A group that the project has no objects for is not listed, and a group shows its number of items, such as *3 items*. After the project's own objects come the packages the project refers to, such as **VBA**, **VBRUN** and **VB**, each with its own groups. + +![The Project Explorer in its object view. The project is split into groups of modules, forms, interfaces and user-defined types, each object with the name of its file beside it, above the collapsed VBA, VBRUN and VB packages.](../../Features/Images/9a5c50d5-a9f8-44a7-96f7-ae84548bd7ef.png){:width="423" height="526"} + +Each object has an icon for its kind and, in grey beside its name, the file it is in. The project and its groups are open when you first switch to the view, and the IDE saves which ones you closed with the project. + +- **Double-click an object** opens its form in the designer if it has one. Otherwise it opens the code at the object's declaration, and moves the focus to the editor. +- **Double-click a group**, or select it and press Enter, opens or closes it. Left and Right close and open the selected group. Enter on an object does nothing. +- Up and Down move the selection. + +### Search the objects + +The **Search** button, or the first letter you type with a row selected, opens a search bar over the list. The list shows only the objects whose name contains the text, without regard to case. While a filter is set, the packages and their groups are drawn open, and each group keeps its full count. Esc, or the bar's close button, closes the bar and brings back the whole list. + + + +> [!NOTE] +> In twinBASIC BETA 1005, the object view has some defects. +> +> - A right click on a row opens no menu, so the menu's **View Object**, **View Code**, **Add**, **Rename** and **Delete** cannot be reached. To rename or delete an object's file, press Ctrl+R to return to the file view. +> - Shift+double-click on a form opens its designer, like a plain double-click, and not its code. To open the code, switch to the file view and open the form's `.twin` file. +> - When the search bar opens because you typed a letter, it holds `>` before the letter. The `>` does not change what is matched. + +## See Also + +- [Files and folders](Files-and-Folders) -- the right-click menu, and renaming, moving and deleting +- [Adding files](Adding-Files) -- the **Add** menu +- [Navigating](../Code/Navigating) -- Go To Definition, **OUTLINE** and **OPEN EDITORS** +- [View menu](../Reference/Menu/View) -- the command that shows the panel +- [IDE Options](../Customising/IDE-Options#project-explorer-tabs-and-start-up) -- the options of the Project Explorer diff --git a/docs/IDE/Projects/References-and-Packages.md b/docs/IDE/Projects/References-and-Packages.md new file mode 100644 index 00000000..b3c4bf15 --- /dev/null +++ b/docs/IDE/Projects/References-and-Packages.md @@ -0,0 +1,159 @@ +--- +title: References and packages +parent: Projects and files +grand_parent: IDE +nav_order: 4 +permalink: /tB/IDE/Projects/References-and-Packages +index: + - references + - library references + - type libraries + - com references + - packages in the ide + - package needed + - enabled libraries +--- + +# References and packages + +A project uses code from libraries. A library is a type library registered on the machine, or a twinBASIC package. This page describes the part of the **Project Settings** dialog that manages them: the lists, the ticks, the questions it asks, and the way a library is kept in the project. The language side of packages, such as how to build and publish one, is in [Package Management](../../../Features/Packages/). + +## Open the lists + +The lists are the **Library References** section of [Project Settings](../Project-Settings#library-references). In the project's `Settings` file the setting is `project.references`. + +- **Project → References...** (Ctrl+T) opens the dialog with its filter box holding `project.references`, so that only this section shows. +- The gear in the **PROJECT EXPLORER** title bar, and **Project → Project Settings...**, open the whole dialog. Type `project.references` in the filter box to reach the section. +- The **GoTo COM References** button of the box that [**More components...**](../Forms/Toolbox#add-activex-controls-and-components) opens in the Toolbox shows the dialog on the **Available COM References** tab. +- A reference that cannot be loaded opens it by itself, about a second after the project has loaded. See [A reference that fails](#a-reference-that-fails). + +## The three tabs + +Three buttons above the lists choose which one shows. + +| Tab | Lists | +|---|---| +| **Enabled Libraries** | The libraries the project uses, in order of priority. | +| **Available COM References** | Every type library that the compiler finds on the machine. The list is read again each time you choose the tab. A search box over the names filters it by name or path. | +| **Available Packages** | The packages on the TWINSERV package server, the packages in your local packages folder, and the packages the project embeds. The IDE asks the server each time you choose the tab. | + +To use a library, tick it in one of the two lists of available libraries. To stop using one, untick it in any list. **Apply Changes** puts the change into effect. + +## The Enabled Libraries list + +![The Project Settings dialog on its Enabled Libraries tab, listing four ticked libraries in order of priority, with columns for the library symbol and the version.](../Images/ProjectSettings_LibraryReferences.png){:width="1102" height="774"} + +The list begins with two rows that cannot be moved: the **VBA** and **VBRUN** compatibility packages, marked `[COMPILER PACKAGE]`. Unticking one does not remove it. It switches the package off for the project, with the settings `project.disablePackageVBA` and `project.disablePackageVBRUN`. The packages that ship with the IDE show `[BUILT-IN]` as their publisher and the version of the IDE. + +Each row has these columns: + +- the tick, the name and two arrows; +- **Library Symbol**, **Version**, **Publisher**, **Path**, **LibraryID**, **Locale**, **Licence** and **Date**; +- **Use ActiveX Controls**, which is ticked unless you clear it; +- **ActiveX Fusion Mode** and **Fusion: Async Events**, which show only when the IDE's Fusion mode is on. See [Fusion](../../../Features/Fusion). + +A **Path** column shows a `win32:` line and a `win64:` line when the two differ. + +A package that the project embeds is marked `[EMBEDDED-PACKAGE]`, and a package that is kept outside the project is marked `[LINKED-PACKAGE]`. See [Linked Packages](../../../Features/Packages/Linked). + +Unticking a row removes the reference. For a package that is kept under `Packages`, it also deletes the package's folder from the project. [Updating a Package](../../../Features/Packages/Updating) describes what to do to replace a package. + +### Priority + +The list is in order of priority. The two pink arrows of a row move it up, which gives it a higher priority, or down, which gives it a lower one. An arrow that cannot move the row is greyed out. The two compiler packages stay at the top. + +### The library symbol + +A library's *symbol* is the name its components are qualified with in code. It is read from the library, and shows `...` until the IDE has it. The pencil beside the symbol has the tooltip **Click here to customize the library symbol used in this project**, and opens a text box. A symbol that you type is stored as an override, with no spaces: Enter keeps it and Esc returns to the original. The row then shows the original struck through, and the override beside it. [Library Symbols](../../../Features/Packages/Library-Symbols) describes what a symbol does. + +### A reference that fails + +A reference that the compiler cannot load shows **ERROR unable to load this reference** and a **FIX** link. About a second after the project loads, the dialog opens by itself to show it. It opened again after an **Apply Changes** that restarted the compiler. **FIX** does nothing but say that the feature is not implemented yet, and that you should remove the reference and add it again from **Available COM References**. A library listed twice shows **ERROR duplicate reference** on both rows. + + + +## Available COM References + +![The Project Settings dialog on its Available COM References tab. A search box sits above an alphabetical list of unticked type libraries registered on the machine, with columns for the library symbol, the version and the publisher.](../Images/ProjectSettings_AvailableCOMReferences.png){:width="1102" height="774"} + +Tick a library to add it to the project. The reference is added to `project.references` with `autoCtlExt` set to true. A change makes **Apply Changes** available. + +## Available Packages + +The tab lists the public packages of TWINSERV. After you sign in, it lists your private packages too. A yellow tip under the list, **TIP: LOGIN to see any PRIVATE packages you've made**, opens the sign-in form, with tabs to log in and to register, and the box **Remember password on this device**. After you sign in, choose the tab again to refresh the list. + +![The Project Settings dialog open over the IDE, with red numbers marking the route: the Project Explorer's gear, the Library References heading and the Available Packages tab. That tab lists the built-in and published packages with tick boxes and Embedded and Library Symbol columns.](../../Features/Packages/Images/e749e10f-e361-4f15-a977-d756fcb3b5dd.png){:width="1162" height="529"} + +Tick a package to add it. The **Embedded** column marks a package whose copy is part of the project. Clearing its tick makes the package *linked*: the project refers to it by its identifier, and the file is in `%APPDATA%\twinBASIC\packages`. [Linked Packages](../../../Features/Packages/Linked) describes the two ways, and [Importing a Package from TWINSERV](../../../Features/Packages/Importing-TWINSERV) the steps. + +![The Available Packages tab with a package ticked. One red arrow points at the Embedded column's heading, and another at the tick in that column on the package's row.](../../Features/Packages/Images/1f7e3574-f3c8-4aee-972a-ff161c0e51ac.png){:width="830" height="181"} + +The IDE asks you a question in three cases. + +- **You tick a package that is in your local packages folder and on TWINSERV.** A box shows the two versions, and offers **Use Local Package (LINK)**, **Download it from TWINSERV (EMBED)** and **Cancel**. With only one source, the IDE uses it without asking. +- **You clear the Embedded tick of an embedded package.** If a copy of the package is already in the local folder, a box shows both versions and offers **Use Existing Local Package**, **Overwrite Local Package (export it from this project)** and **Cancel**. If there is none, the IDE writes the package to the local folder, as `.twinpack`, and removes the copy from the project. +- **You tick the Embedded column of a linked package.** The box offers **Import Local Version**, **Import TWINSERV version** and **Cancel**, when both exist. + +![The prompt over the Available Packages list saying that the local package already exists, giving the local and TWINSERV versions, with three buttons: use the local package as a link, download it from TWINSERV to embed it, and cancel.](../../Features/Packages/Images/f48a7254-e5c9-48c5-8099-725c0951ae5f.png){:width="580" height="438"} + +Replacing an embedded package by a newer build, and the case of a linked package that is missing from the machine, are described in [Updating a Package](../../../Features/Packages/Updating) and [Linked Packages](../../../Features/Packages/Linked#opening-a-project-with-missing-linked-package). + +## Import from file + +The **Import from file...** button under the lists opens the Windows **Open** dialog. What it imports depends on the tab. + +- On **Available COM References**, and on **Enabled Libraries**, it asks for a type library. The IDE copies the file into the project as `ImportedTypeLibraries/`, and adds it to the references at once, ticked. +- On **Available Packages**, it asks for a `.twinpack` file. The package is added to the **Available Packages** list. [Importing a Package from a TWINPACK File](../../../Features/Packages/Importing-TWINPACK) gives the steps. + +> [!NOTE] +> In twinBASIC BETA 1005, a package imported with **Import from file...** is listed but not ticked, so the project does not use it. Tick it yourself after the import. + +> [!NOTE] +> In twinBASIC BETA 1005, **Import from file...** puts a copy of the package under the project's `Packages` folder. Closing the dialog with **Cancel** leaves the copy there, and the project is not marked as changed. + +> [!NOTE] +> In twinBASIC BETA 1005, a type library added with **Import from file...** is drawn on the **Enabled Libraries** list as `[LINKED-PACKAGE]`, and on **Available COM References** it is listed twice, once from the project and once from the registered library, both ticked. Clearing the tick of either row removes the reference. + +## Package needed + +Choosing an **Add** item for a Windows form without the **WinNativeForms** package in the project, or for a CustomControls form without the **CustomControls** package, shows a box, **Package needed**, and the name of the package. It says that the package must be added first, and that the compiler restarts. The button **Add WinNativeForms package**, or **Add CustomControls package**, adds the reference to the `Settings` file and restarts the compiler. It creates nothing: choose the **Add** item again. **Cancel** changes nothing. [The package prompts](../Forms/Designer#the-package-prompts) shows the boxes. + +The reference is listed under the package's own name, `WinNativeForms` or `CustomControlsPackage`, until the compiler has answered, and then under the name of the library, such as `twinBASIC - VB Compatibility Package (Forms)`. + +> [!NOTE] +> In twinBASIC BETA 1005, in a project that has a file, the button also saves the project, although the box speaks only of restarting the compiler. A project with no file yet is not saved, and restarts from memory. + +## Apply Changes and closing the dialog + +The dialog has a filter box, **Apply Changes** and **Cancel**. **Apply Changes** is greyed out until you change something. It writes the `Settings` file and prints `[COMPILER] Project settings updated` to the Debug Console. When the change needs it, the compiler is restarted, and the project is saved first: the console prints `Project settings changes require compiler-restart`, `saving to disk [DONE]` and `restarting from FILE`. + +**Cancel** closes the dialog at once and drops every change, whichever it is, without asking. Esc does the same when the focus is in the filter box. The close button in the title bar asks first, in a box, **WARNING: you made changes but haven't saved them. Close without saving?**, with **Yes, close** and **No, keep editing**. + + + +> [!WARNING] +> In twinBASIC BETA 1005, the close button of the title bar does not ask when the only change is to the references. The dialog closes, the change is dropped, and nothing says so. The code that compares the settings leaves out the compiler warnings as well. Press **Apply Changes** before you close the dialog. + +## The References folder + +The `References` folder of the Project Explorer has one entry for each library the project uses. The entry is named with the library's symbol and its identifier. It is not a file of the project, and it is not in the saved `.twinproj`. A double-click opens it in the code editor, as the declarations that the compiler generates for the library, with a comment that names the library's original file. + +**Cut**, **Rename** and **Delete Permanently** are greyed out on the right-click menu for these entries. + +> [!NOTE] +> In twinBASIC BETA 1005, the Delete key removes a `References` entry from the tree, although its menu item is greyed out. The reference itself stays in the project. To remove a reference, untick it in the **Enabled Libraries** list. + +## Where the project keeps them + +- The references are in the `project.references` list of the `Settings` file, with the symbol overrides. +- An embedded package is a folder under `Packages`. A package's files are read-only in the Project Explorer. +- A type library imported from a file is a file in `ImportedTypeLibraries`. +- A linked package is a file in `%APPDATA%\twinBASIC\packages`. The project refers to it by the package's identifier. + +## See Also + +- [Project Settings](../Project-Settings#library-references) -- the setting, and the rest of the dialog +- [Package Management](../../../Features/Packages/) -- creating, importing, linking and updating packages +- [Library Symbols](../../../Features/Packages/Library-Symbols) -- the name a library's components are qualified with +- [Adding files](Adding-Files) -- the other items of the **Add** menu +- [Project menu](../Reference/Menu/Project) -- **References...** and **Project Settings...** diff --git a/docs/IDE/Projects/Saving-and-Exporting.md b/docs/IDE/Projects/Saving-and-Exporting.md new file mode 100644 index 00000000..50582113 --- /dev/null +++ b/docs/IDE/Projects/Saving-and-Exporting.md @@ -0,0 +1,171 @@ +--- +title: Saving and exporting +parent: Projects and files +grand_parent: IDE +nav_order: 5 +permalink: /tB/IDE/Projects/Saving-and-Exporting +index: + - save a project + - save as + - close a project + - recent projects + - export project + - unsaved project +--- + +# Saving and exporting + +The project lives in memory until you save it. This page describes how the IDE saves it, what marks it as changed, what happens when you close it or open another, and **Export Project**, which writes it out as ordinary files. + +## Save Project +{: #save-project } + +**File → Save Project** (Ctrl+S), and the toolbar button **Save All Changes**, write the whole project to its `.twinproj` file. First every open editor saves its text, the code editors and the designers alike. Then the compiler writes the file. The Debug Console prints `[PROJECT] twinBASIC project saving to disk [DONE]` in green when it has finished. + + + +The command works on a project that has no changes, and writes the file again. For a project with no file yet, it opens the **Save As** dialog first. See [A project with no file](#a-project-with-no-file). + +There is no save for a single file: **File → Save Current Document** is always greyed out, and has no key. The IDE has no automatic save and no automatic backup. [Save often](../Code/Editor#save-often) says what the IDE keeps for you and what it does not. + +### The changed mark + +A project with changes that are not saved shows a dot before its name in the title bar: `• project.twinproj - twinBASIC`. The title is the project's file name, then the name and version of the IDE. Saving removes the dot. + + + +These make a project changed: + +- creating, renaming, moving, deleting or importing a file or folder; +- an edit in any editor or designer that is not saved; +- setting or clearing a breakpoint. + +### When a save fails + +The IDE gives the compiler 10 seconds to save the open documents. If it does not answer, a box says that the IDE timed out while trying to save them, and advises you to make backups of your documents by hand. The compiler then has 20 seconds to write the project file. If it does not answer, a box says that the IDE timed out while trying to save the project, and that the compiler restarts and you should try again. Choose **OK** to restart it. + +If the compiler can write no file, an alert says **save project failed**, with a result code and the Windows error, such as `ERROR_ACCESS_DENIED` or `ERROR_DISK_FULL`, and asks you to check that the path is writable. The project stays open, changed, with its dot. Nothing is lost. + +The compiler can also ask the IDE for another path: a box, **Failed to save the project. Check the project file path and adjust if necessary.**, holds the project's path in a text box, and offers **Try Again**, which saves to the path in the box and keeps it as the project's path, and **Cancel**. + +### Other commands that save + +Some commands save the project besides **Save Project**: **Save Project As** saves after it chooses the path, and **Apply Changes** in [Project Settings](References-and-Packages#apply-changes-and-closing-the-dialog) saves when the compiler restarts. With the setting [Export After Save](../Project-Settings#export-after-save), a save runs **Export Project** first. + +> [!NOTE] +> In twinBASIC BETA 1005, several actions save the project although you did not ask. They are [**Import...**](Adding-Files#the-project-is-saved) of ordinary files; the **Import** and **Cancel** buttons of the **Import from twinproj...** dialog; [renaming the project](Files-and-Folders#the-project); and the button of a [Package needed](References-and-Packages#package-needed) box in a project that has a file. Importing ordinary files, **Cancel** in the import dialog and renaming the project write the unsaved changes of the open editors into the file as well. + +## Save Project As + +**File → Save Project As...** opens the Windows **Save As** dialog, with the project's name proposed. The project's file becomes the one you choose, and the IDE saves the project there. The old file stays as it was. The new path goes to the top of the [recent list](#recent-projects), and the title bar shows the new name. The folder of the new file becomes `${SourcePath}`, for the settings that use it. The command has no key. + +## A project with no file + +A project made from a template or a sample, from **Import from folder...**, or from a VB6 project has no file until it is saved. The title bar says `Unsaved.twinproj`. **Save Project** asks for a file name first, with the **Save As** dialog, and then saves. An import that saves the project asks for a file name in the same way. + +**Open Project Folder...** and **Open Build Output Folder...** of the **Project** menu show the notification **Project is not yet saved. Please save the project first.** for such a project. + +## What the IDE remembers about a project + +The IDE keeps the state of a project apart from its files: the editors that are open, with their view state, which folders of the Project Explorer are open, the watches, the bookmarks, the history of the Debug Console, of **FIND / REPLACE** and of the Memory panes, and the settings of some panels. It saves this state every five seconds. The open editors come back when you open the project again only if **Restore Editors State When Opening Project** is on. The watches and the history of the Debug Console come back whatever the option says. + +The state is kept in the registry, in a value for each project path, under `ProjectState` beside the IDE's settings. See [where the IDE keeps its settings](../Customising/#where-the-ide-keeps-its-settings). Ctrl+S does not write it into the `.twinproj`. By the IDE's code, **Save Project As** also stores a copy in the new file, as the hidden file `.meta`, which the Project Explorer does not draw. + +## Close Project and Exit + +**File → Close Project** closes the project. If it has changes that are not saved, a box asks **You've made changes to this project. Save now?**, with three buttons. + + + +- **Save** saves the project, with the **Save As** dialog first if it has no file, and then closes it. +- **Discard Changes** closes it and leaves the file on disk as it was. +- **Cancel** keeps the project open. + +**File → Exit** (Alt+F4), and the close button of the window, ask the same question. If the save fails, the alert described above appears and the project stays open. Closing ends the compiler process of the project. **Close Project** has no key. + +## Open a project + +- **File → New Project...** (Ctrl+N) and **File → Open Recent...** open the **New / Open Project** dialog, which has the tabs **New**, **Samples** and **Recent**. **Open Recent...** starts on the **Recent** tab. A **Recent (VB6)** tab shows too when the machine has a VB6 history. [New Project](../Project/New) describes the dialog. +- **File → Open Project...** (Ctrl+O) opens the Windows **Open** dialog. A `.vbp` file is imported as a VB6 project; the result is unsaved. A project opened with **Import from folder...** is unsaved as well. + +The project that is open is closed before the new one loads, and the question above comes at that point. In the **New / Open Project** dialog, it comes when you press **Open**, not before. + +### Recent projects + +The **Recent** tab lists the full paths of the projects you opened last, the newest first. A double-click, or **Open**, opens one and moves it to the top. The **X** at the end of a row, titled **Remove from this list**, removes the entry at once, with no question. **Save Project As** adds the new path to the top. The list holds 21 entries and is kept in the registry with the IDE's settings. + +A project whose file is gone shows the box **Failed to load the project (error code** *n***)**, with the path and the question **Do you want to remove it from the list of recently opened projects?** The buttons are **Remove It** and **Keep It**. **Keep It** moves the entry to the top. Either way the IDE is left with no project open, because the previous one was closed first. A damaged file opens a native Windows message box instead. + + + +## Open a folder + +**Project → Open Project Folder...** opens the folder of the `.twinproj` file in Windows Explorer. **Project → Open Build Output Folder...** opens the folder of the file that the [Build Output Path](../Project-Settings#build-output-path) names. The command does not create the folder. With no build output path set, it gives the same notification as for a project with no file. + +## Export Project + +Writes the open project out to a folder as separate files, instead of the single `.twinproj` file. The folder gets the project's `Settings` file, its `Sources`, `Resources` and other folders, and a `Packages` folder with the full source of every package the project references. For a small project that uses the **VB** package, the export held 477 files: two of the project's own, and 475 under `Packages`. Ctrl+E runs the same command. + +**Before it writes anything, the command deletes everything already in the target folder.** It does not ask first, and the deleted files do not go to the Recycle Bin. Files that have nothing to do with the project are deleted too: hidden files, a `.git` folder, anything else there. + +> [!WARNING] +> Point **Export Project** only at a folder that holds nothing but an earlier export of the same project. Never point it at a folder that holds anything else, at the top folder of a Git repository, or at the folder that holds the `.twinproj` file. + +To write only some of the files, use [**Export...**](Files-and-Folders#export-a-file) on the right-click menu of the Project Explorer. + +### Where it writes + +- **With [*Export Path*](../Project-Settings#export-path) set**, the command exports there straight away, with no dialog. +- **With no *Export Path***, it opens a *Browse For Folder* dialog, which starts in the folder that holds the `.twinproj`. The IDE appends the project's name and a backslash to the path the dialog returns, with no separator before the name, and the export goes into that folder. It is that folder that is emptied. + +With [*Export After Save*](../Project-Settings#export-after-save) set, every save runs the export again before it writes the project, into *Export Path*, and empties that folder again. + +> [!NOTE] +> In twinBASIC BETA 1005, when the `Settings` file has an *Export Path* but no `project.exportPathIsV2` entry, the project's name is joined to the path with no separator: `${SourcePath}\exp2` exports into `exp2ProjTry\` for a project named `ProjTry`. + +### When a file cannot be deleted + +A read-only file stops the export part-way. Everything before it in alphabetical order is already deleted by then, everything after it is left, and nothing is written. No message appears. The only record is in the [Debug Console](../Debugging/Debug-Console): + +```text +[EXPORT] DELETE FAILED: \\?\C:\Work\MyApp\notes.txt +[EXPORT] ERROR: unable to clean the output folder +[EXPORT] export failed. +``` + +Git makes the files in `.git\objects` read-only. When the target is the top folder of a repository, the command deletes `.git\config`, `HEAD`, `index`, `hooks` and `info`, then stops at the first object file. Git no longer recognises what is left as a repository. + +A target that cannot be made at all, such as a folder on a drive that does not exist, gives the same two `ERROR` lines and no box. + +### Exporting into the project's own folder + +When the target is the folder that holds the `.twinproj`, the command deletes the `.twinproj` file too. The project then exists only in the open IDE, until **Save Project** (Ctrl+S) writes the file back. For this reason the Project Settings dialog refuses `${SourcePath}` on its own as the *Export Path*, but it accepts the same folder written out in full. + +### Packing the export back into a project + +The `Packages` folder holds the compiler packages as well. For a project with the default references they are **VB**, **VBA**, **VBRUN** and the package behind the **App** object, in folders named `VB`, `VBA`, `VBRUN` and `AppGlobalClassProject`. Every other compiler package the project references gets a folder too, named after the package's own project, which is not always the name the reference uses: the WebView2 sample references `WebView2Package` and `WindowsControlsPackage`, and its export has folders named `WebView2Package` and `VB`, because `WindowsControlsPackage` is the VB package. The project's `Settings` file marks each compiler package's reference `"isCompilerPackage": true`; nothing inside the package's own folder does. + +A `.twinproj` file that the IDE saved does not hold the compiler packages, and the `export` command of the tB executable does not write them. A package the project embeds is different: one added from TWINSERV or from a TWINPACK file is embedded by default (see [Linked Packages](../../../Features/Packages/Linked)), is part of the saved `.twinproj`, and has a folder under `Packages` too. + +**Delete the compiler packages' folders before packing the export back into a project.** The IDE's own way to pack it is **Import from folder...** in the [New Project](../Project/New#import-from-folder) dialog, which opens the project unsaved; the first save asks for a file name. The [import/export script](../../../Features/Packages/Import-Export-Tool#usage)'s `import` packs it as well. Both pack every folder under `Packages` into the project, so the compiler packages become a copy inside it. Rebuilt by **Import from folder** with them, the project was 4,222,833 bytes, against 4,207 bytes without them and 2,956 bytes for the project as the IDE saved it. Both rebuilt projects open with no errors, and the script's project is the same 4.2 MB. + +The compiler does not use that copy. A function added to the copy of **VBA**, in `Packages\VBA\Sources\Math.twin`, is an unrecognized symbol (TB5079) to the code that calls it. But every later export writes the copy back into `Packages`: the added function is there again after each save, and the Debug Console reports `[EXPORT] COMPLETED (139 folders, 954 files)`, where the original project's export reported `(72 folders, 479 files)`. So after an IDE update, the export still holds the package source of the IDE that first exported the project, while the project compiles against the packages of the IDE in use. + +The tB executable's `import` cannot pack a folder while any folder remains under `Packages\`. It stops at the first one, writes nothing, and exits with code `999` --- see [Where the two differ](../../../Features/Packages/Import-Export-Tool#where-the-two-differ). With the compiler packages' folders deleted, it packs the export of a project that embeds no package. [Keeping a project in Git from the IDE](../../../Features/Packages/Import-Export-Tool#keeping-a-project-in-git-from-the-ide) keeps them out of the repository from the start. + +### What the Debug Console shows + +Each export writes a first line, `[EXPORT] exporting current project to "…"`, and a last line: `[EXPORT] COMPLETED (72 folders, 478 files)`, or the failure lines above. With [*Export Verbose*](../Project-Settings#export-verbose) set, it also writes a line for each file and folder it deletes, `[EXPORT] DELETED: …`, and for each file it writes, `[EXPORT] DONE: …`. If the compiler answers the IDE's request with an error code, a box reads **ERROR: exportProject failed.** and the code. + + + +The `export` command of the tB executable and of the import/export script deletes nothing. See [What both programs do](../../../Features/Packages/Import-Export-Tool#what-both-programs-do). + +## See Also + +- [Project Explorer](Project-Explorer) -- the tree of the project's files +- [Files and folders](Files-and-Folders) -- the commands that change files, and **Export...** for a few files +- [Project Settings](../Project-Settings#export) -- Export Path, Export After Save and Export Verbose +- [New Project](../Project/New) -- the dialog that opens or imports a project +- [File menu](../Reference/Menu/File) -- the commands of the menu +- [Import/Export Tool](../../../Features/Packages/Import-Export-Tool) -- keeping a project in Git as plain-text files diff --git a/docs/IDE/Projects/index.md b/docs/IDE/Projects/index.md new file mode 100644 index 00000000..a9837130 --- /dev/null +++ b/docs/IDE/Projects/index.md @@ -0,0 +1,57 @@ +--- +title: Projects and files +parent: IDE +nav_order: 3 +permalink: /tB/IDE/Projects/ +has_toc: false +index: + - project + - twinproj + - project file + - files in a project +--- + +# Projects and files + +A project is a set of files that the compiler holds in memory, and the IDE keeps a copy of the set and shows it in the **PROJECT EXPLORER**. On disk, the project is one `.twinproj` file. This chapter describes how to see the files, add them, change them and keep them. + +- [**Project Explorer**](Project-Explorer) --- the panel, its file view and object view, what a click opens, and the special folders. +- [**Files and folders**](Files-and-Folders) --- the right-click menu, and renaming, moving, copying, exporting and deleting. +- [**Adding files**](Adding-Files) --- the **Add** menu, importing files and projects, and resources. +- [**References and packages**](References-and-Packages) --- the libraries a project uses, and the packages it embeds or links. +- [**Saving and exporting**](Saving-and-Exporting) --- Save, Save As, closing, the recent list, and **Export Project**. + +The dialog that holds the project's settings has a page of its own, [Project Settings](../Project-Settings). The commands of the **File** and **Project** menus are listed in the [File menu](../Reference/Menu/File) and [Project menu](../Reference/Menu/Project) reference pages. + +## The project is in memory + +A project is not a folder on disk that the IDE reads and writes. The compiler process holds the files, and the IDE asks it for every operation: read a file, create one, move one, delete one. Two results follow. + +- **Adding, renaming, moving and deleting change the project in memory.** They reach the disk when the project is saved. **File → Save Project** writes the whole project to the `.twinproj` file, and a few other actions save it too. [Saving and exporting](Saving-and-Exporting) describes it. +- **A change made outside the IDE is not noticed.** There is nothing to watch: the files that the Project Explorer shows are not files on disk. Windows Explorer cannot drop a file into the tree, and the clipboard commands cannot take a file from Windows. [Adding files](Adding-Files#import) shows how to bring a file in. + +A path in the IDE is written `///`, and **Copy Path** puts exactly this on the clipboard. It is not a path on disk. + +A project made from a template or a sample, or opened from a folder or a VB6 project, has no file yet. The title bar says `Unsaved.twinproj`, and the first save asks for a file name. + +## The parts of a project + +A project holds these top-level folders. The Project Explorer draws all but `Settings`. + +| Folder | Holds | +|---|---| +| `Sources` | The code: `.twin`, `.bas` and `.cls` files, and the designer files of forms, user controls, property pages and reports. | +| `Resources` | The files that the build embeds in the program. See [Resources](Adding-Files#resources). | +| `References` | One entry for each library the project refers to. See [References and packages](References-and-Packages#the-references-folder). | +| `Packages` | The packages that the project embeds, and the compiler packages `VB`, `VBA` and `VBRUN`. | +| `ImportedTypeLibraries` | The type libraries that were imported from a file. See [Import from file](References-and-Packages#import-from-file). | +| `Miscellaneous` | Empty in a new project. | +| `Settings` | The project's settings, as JSON. [Project Settings](../Project-Settings) edits them. | + +## See Also + +- [Project Settings](../Project-Settings) -- the settings of the project, with a section for each +- [Writing code](../Code/) -- the editor that opens the code files +- [Designing forms](../Forms/) -- the designer that opens the form files +- [New Project](../Project/New) -- making a project from a template, a sample or a folder +- [Package Management](../../../Features/Packages/) -- the language side of packages diff --git a/docs/IDE/index.md b/docs/IDE/index.md index ee299295..a3cc931c 100644 --- a/docs/IDE/index.md +++ b/docs/IDE/index.md @@ -8,7 +8,7 @@ permalink: /tB/IDE ![The twinBASIC IDE with no project loaded. A menu bar and toolbar run across the top, the Toolbox is docked on the left, an empty Editor 1 fills the centre, and Project Explorer sits above Properties on the right. Debug Console, Diagnostics, Call Stack and Variables share a row along the bottom. Every pane is empty, and the status bar reports tB Services unavailable and tB Licence not ready.](Images/IDE.png){:width="1920" height="1032"} -The IDE consists of several fixed panes and tool windows. The [**Project Explorer**](IDE/Project/Explorer) shows the file tree of the open project; the [**Editor**](IDE/Code/Editor) is the main code and designer surface; the [**Properties**](IDE/Forms/Properties) pane shows and edits properties for the selected item; the [**Toolbox**](IDE/Forms/Toolbox) lists the controls available to drop onto a form. +The IDE consists of several fixed panes and tool windows. The [**Project Explorer**](IDE/Projects/Project-Explorer) shows the file tree of the open project, and [**Projects and files**](IDE/Projects/) describes how to add, change and save its files; the [**Editor**](IDE/Code/Editor) is the main code and designer surface; the [**Properties**](IDE/Forms/Properties) pane shows and edits properties for the selected item; the [**Toolbox**](IDE/Forms/Toolbox) lists the controls available to drop onto a form. The debugging panels --- [**Call Stack**](IDE/Debugging/Inspecting#call-stack), [**Variables**](IDE/Debugging/Inspecting#variables), [**Debug Console**](IDE/Debugging/Debug-Console), [**Watches**](IDE/Debugging/Inspecting#watches) and [**Memory**](IDE/Debugging/Memory) --- are described in [**Running and debugging**](IDE/Debugging/). Nothing opens them when a program stops. The Call Stack, Variables and Debug Console are in the default layout. Watches and Memory are not: open them from the **View** menu. diff --git a/docs/_book.yml b/docs/_book.yml index 2d001ca0..16803381 100644 --- a/docs/_book.yml +++ b/docs/_book.yml @@ -267,6 +267,11 @@ parts: no_outline_entry: true no_heading_shift: true outline_closed: true + - title: Projects and files + landing_page: /tB/IDE/Projects/ + page: /tB/IDE/Projects/ + landing_is_target: true + outline_closed: true - title: Project Settings page: /tB/IDE/Project-Settings no_outline_entry: true @@ -310,7 +315,6 @@ parts: outline_closed: true - title: IDE Reference pages: - - /tB/IDE/Reference/Menu/File - /tB/IDE/Reference/Toolbar outline_closed: true @@ -715,10 +719,8 @@ left_out: - reason: IDE pages that are still screenshots and the labels they show, or headings with nothing under them no_descent: true pages: - - /tB/IDE/Project/Explorer - /tB/IDE/AddIns/Community - /tB/IDE/Reference/Menu - - /tB/IDE/Reference/Menu/Project - /tB/IDE/Reference/Menu/AddIns - /tB/IDE/Reference/Menu/Help @@ -731,7 +733,9 @@ left_out: - /tB/IDE/Project/Splash - /tB/IDE/Project/PackagePublishing - /tB/IDE/AddIns/GlobalSearch + - /tB/IDE/Reference/Menu/File - /tB/IDE/Reference/Menu/Edit + - /tB/IDE/Reference/Menu/Project - /tB/IDE/Reference/Menu/Format - /tB/IDE/Reference/Menu/Run - /tB/IDE/Reference/Menu/Debug From cc7937c6fd856080352c54b24d1e873afad7c752 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:15:14 +0200 Subject: [PATCH 02/17] indexer sync: take the first version TWINSERV lists, its newest, not the last, which was the oldest (every contributed section with more than one version was indexed from its first release) --- indexer/TWINSERV-protocol.md | 10 ++++++++-- indexer/lib/sync.mjs | 7 +++++-- test/indexer.test.mjs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/indexer/TWINSERV-protocol.md b/indexer/TWINSERV-protocol.md index ac9f328f..bee49faf 100644 --- a/indexer/TWINSERV-protocol.md +++ b/indexer/TWINSERV-protocol.md @@ -86,9 +86,15 @@ List all packages visible to the current session. } ``` -The `versions` array is ordered newest-first. Each entry within a publisher +The `versions` array is ordered newest-first, so the latest version is +`versions[0]`. The order is the server's, and it is not always the order of the +version numbers: on 2026-10-12 forliny's `{CA836295-...}` listed WinReg 1.0.1.1 +and 1.0.0.1 before WinSysTray 1.0.2.0 and 1.0.1.0, as if the fourth part were +compared before the third. Each entry within a publisher group shares the same `projectId` (a GUID) but may differ in `symbol` or -`description` across versions. +`description` across versions: Krool's TwinTimerPackage 1.0.0.0 became +TwinTimerLib from 1.0.2.0, and forliny's GUID holds two libraries, WinReg and +WinSysTray (with TbSysTray 1.0.0.0 between them). As of June 2026, 32 public packages are listed. diff --git a/indexer/lib/sync.mjs b/indexer/lib/sync.mjs index c90fcd1b..2ab40de4 100644 --- a/indexer/lib/sync.mjs +++ b/indexer/lib/sync.mjs @@ -2,8 +2,11 @@ import { readFile } from "node:fs/promises"; import { queryPackages, downloadPackage } from "./twinserv-client.mjs"; import { readPackageFiles } from "./package-files.mjs"; +// TWINSERV lists a package's versions newest first, by its own rule: forliny's +// {CA836295-...} lists WinReg 1.0.1.1 before WinSysTray 1.0.2.0. The newest is the +// first listed, never the highest number and never the last. function latestVersion(pkg) { - return pkg.versions[pkg.versions.length - 1]; + return pkg.versions[0]; } function versionString(v) { @@ -59,4 +62,4 @@ async function fetchPackage(projectId, version) { return readPackageFiles(await downloadPackage(projectId, version)); } -export { compareWithManifest, fetchPackage, versionString }; +export { compareWithManifest, fetchPackage, latestVersion, versionString }; diff --git a/test/indexer.test.mjs b/test/indexer.test.mjs index 8f249453..4576e746 100644 --- a/test/indexer.test.mjs +++ b/test/indexer.test.mjs @@ -58,6 +58,7 @@ import { storeStatus, writeToStore, } from "../indexer/lib/store.mjs"; +import { latestVersion, versionString } from "../indexer/lib/sync.mjs"; import { CONTAINER_MAP, preprocessVB6 } from "../indexer/lib/vb6-preprocess.mjs"; const SAMPLE = path.join(import.meta.dirname, "../indexer/sample.twinpack"); @@ -1192,6 +1193,39 @@ describe("auditCoverage", () => { // ----------------------------------------------------------- the store's sync state +describe("latestVersion", () => { + const v = (symbol, versionMajor, versionMinor, versionRevision, versionBuild) => ({ + symbol, + versionMajor, + versionMinor, + versionRevision, + versionBuild, + }); + + test("is the first version TWINSERV lists, never the last", () => { + const pkg = { + versions: [v("tbFileSysTools", 1, 8, 0, 0), v("tbFileSysTools", 1, 2, 0, 0), v("tbFileSysTools", 1, 1, 1, 0)], + }; + assert.equal(versionString(latestVersion(pkg)), "1.8.0.0"); + }); + + test("even where the first is not the highest number: the server's order decides", () => { + // forliny's {CA836295-...} as TWINSERV listed it on 2026-10-12. + const pkg = { + versions: [ + v("WinReg", 1, 0, 1, 1), + v("WinReg", 1, 0, 0, 1), + v("WinSysTray", 1, 0, 2, 0), + v("WinSysTray", 1, 0, 1, 0), + v("TbSysTray", 1, 0, 0, 0), + v("WinReg", 0, 0, 0, 0), + ], + }; + const latest = latestVersion(pkg); + assert.equal(`${latest.symbol} ${versionString(latest)}`, "WinReg 1.0.1.1"); + }); +}); + // A store folder as `sync` leaves it: sources and an api.json of `version`. const apiText = (version, over = {}) => renderApi({ From f7ca3e20ba2ed14a3b7b749b15c5fa504510733f Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:33:12 +0200 Subject: [PATCH 03/17] TwinTimerLib: the TwinTimerPackage section renamed to the package's current name and moved to 1.0.7.0, its Enabled taking a Boolean --- WIP.md | 2 +- docs/Reference/Contributed.md | 2 +- docs/Reference/Contributed/TBMANLIB/cTimeuse.md | 2 +- .../TwinTimer/Enabled.md | 4 ++-- .../TwinTimer/Interval.md | 2 +- .../TwinTimer/Timer.md | 2 +- .../TwinTimer/index.md | 8 ++++---- .../{TwinTimerPackage => TwinTimerLib}/index.md | 10 +++++----- docs/_book.yml | 6 +++--- .../{TwinTimerPackage => TwinTimerLib}/api.json | 16 ++++++++-------- .../Settings | 10 +++++----- 11 files changed, 32 insertions(+), 32 deletions(-) rename docs/Reference/Contributed/{TwinTimerPackage => TwinTimerLib}/TwinTimer/Enabled.md (87%) rename docs/Reference/Contributed/{TwinTimerPackage => TwinTimerLib}/TwinTimer/Interval.md (96%) rename docs/Reference/Contributed/{TwinTimerPackage => TwinTimerLib}/TwinTimer/Timer.md (96%) rename docs/Reference/Contributed/{TwinTimerPackage => TwinTimerLib}/TwinTimer/index.md (93%) rename docs/Reference/Contributed/{TwinTimerPackage => TwinTimerLib}/index.md (56%) rename indexer/snapshots/contributed/{TwinTimerPackage => TwinTimerLib}/api.json (86%) rename test/example-projects/{contributed-TwinTimerPackage => contributed-TwinTimerLib}/Settings (90%) diff --git a/WIP.md b/WIP.md index 33aaaf4d..6fe57c36 100644 --- a/WIP.md +++ b/WIP.md @@ -34,7 +34,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerPackage, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modPackUnpack` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modPackUnpack` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. diff --git a/docs/Reference/Contributed.md b/docs/Reference/Contributed.md index 48ceb06e..1f253d71 100644 --- a/docs/Reference/Contributed.md +++ b/docs/Reference/Contributed.md @@ -25,6 +25,6 @@ Each package is versioned apart from twinBASIC, and its section says which versi - [**tbRegExp**](tbRegExp/) -- regular expressions, in place of VBScript's **RegExp** object - [**tsJson**](tsJson/) -- a JSON model with parsing, JSONPath queries, JSON Pointer, JSON Patch and JSON Schema validation - [**tsPwGen**](tsPwGen/) -- passwords, PINs and passphrases, with their entropy known before they are generated -- [**TwinTimerPackage**](TwinTimerPackage/) -- a Win32 timer class that reports the elapsed time +- [**TwinTimerLib**](TwinTimerLib/) -- a Win32 timer class that reports the elapsed time - [**VBA_JSON**](VBA_JSON/) -- JSON parsing and serialization, with UTC and ISO 8601 date conversion - [**VBComDlg**](VBComDlg/) -- the **CommonDialog** class, for the Windows common dialogs \ No newline at end of file diff --git a/docs/Reference/Contributed/TBMANLIB/cTimeuse.md b/docs/Reference/Contributed/TBMANLIB/cTimeuse.md index 9db03141..e74e22d5 100644 --- a/docs/Reference/Contributed/TBMANLIB/cTimeuse.md +++ b/docs/Reference/Contributed/TBMANLIB/cTimeuse.md @@ -50,6 +50,6 @@ Stores the current tick count. Calling **Start** again starts a new measurement. - [TBMAN](TBMAN) module -- the shared instance **TBMAN.TimerUse** - [cLogs](cLogs) class -- writes log lines -- [TwinTimerPackage](../TwinTimerPackage/) package -- a Win32 timer class that reports the elapsed time +- [TwinTimerLib](../TwinTimerLib/) package -- a Win32 timer class that reports the elapsed time - [Timer](../../../Modules/DateTime/Timer) function -- the seconds since midnight - [TBMANLIB](.) package -- overview diff --git a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Enabled.md b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Enabled.md similarity index 87% rename from docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Enabled.md rename to docs/Reference/Contributed/TwinTimerLib/TwinTimer/Enabled.md index c2cce72d..4b1298d7 100644 --- a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Enabled.md +++ b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Enabled.md @@ -1,7 +1,7 @@ --- title: Enabled parent: TwinTimer -permalink: /tB/Packages/Contributed/TwinTimerPackage/TwinTimer/Enabled +permalink: /tB/Packages/Contributed/TwinTimerLib/TwinTimer/Enabled has_toc: false --- # Enabled @@ -27,7 +27,7 @@ Enables or disables the timer. Syntax: *object*.**Enabled** **=** *value* *value* -: A **Long** that turns the timer on or off; the property is read as a **Boolean**. Zero (**False**) turns it off; any other value, such as **True**, turns it on. +: A **Boolean** that turns the timer on or off. **False** turns it off; **True** turns it on. Setting **Enabled** destroys any running timer and restarts it under the new setting. When **Enabled** is set to **True**, the timer begins firing only if [**Interval**](Interval) is greater than zero. When **Enabled** is set to **False**, no **Timer** events are raised regardless of the **Interval** setting. diff --git a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Interval.md b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Interval.md similarity index 96% rename from docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Interval.md rename to docs/Reference/Contributed/TwinTimerLib/TwinTimer/Interval.md index 036ec54c..7189368e 100644 --- a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Interval.md +++ b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Interval.md @@ -1,7 +1,7 @@ --- title: Interval parent: TwinTimer -permalink: /tB/Packages/Contributed/TwinTimerPackage/TwinTimer/Interval +permalink: /tB/Packages/Contributed/TwinTimerLib/TwinTimer/Interval has_toc: false --- # Interval diff --git a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Timer.md b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Timer.md similarity index 96% rename from docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Timer.md rename to docs/Reference/Contributed/TwinTimerLib/TwinTimer/Timer.md index 53cf79a1..f92f65e5 100644 --- a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/Timer.md +++ b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/Timer.md @@ -1,7 +1,7 @@ --- title: Timer parent: TwinTimer -permalink: /tB/Packages/Contributed/TwinTimerPackage/TwinTimer/Timer +permalink: /tB/Packages/Contributed/TwinTimerLib/TwinTimer/Timer has_toc: false --- # Timer diff --git a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/index.md b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/index.md similarity index 93% rename from docs/Reference/Contributed/TwinTimerPackage/TwinTimer/index.md rename to docs/Reference/Contributed/TwinTimerLib/TwinTimer/index.md index ced5092a..92bc7ba6 100644 --- a/docs/Reference/Contributed/TwinTimerPackage/TwinTimer/index.md +++ b/docs/Reference/Contributed/TwinTimerLib/TwinTimer/index.md @@ -1,7 +1,7 @@ --- title: TwinTimer -parent: TwinTimerPackage Package -permalink: /tB/Packages/Contributed/TwinTimerPackage/TwinTimer/ +parent: TwinTimerLib Package +permalink: /tB/Packages/Contributed/TwinTimerLib/TwinTimer/ has_toc: false --- @@ -44,7 +44,7 @@ Setting **Enabled** to **True** while **Interval** is `0` does not start the tim Syntax: *object*.**Enabled** [ = *value* ] *value* -: A **Long**; the property is read as a **Boolean**. Zero (**False**) suppresses events; any other value, such as **True**, allows them. +: A **Boolean**. **False** suppresses events; **True** allows them. > [!NOTE] > **Enabled** defaults to **True** at construction. A freshly constructed **TwinTimer** with **Interval** = `0` (the initial default) does not fire until **Interval** is set to a positive value. @@ -111,4 +111,4 @@ End Sub ## See Also -- [TwinTimerPackage](../) package -- overview and installation +- [TwinTimerLib](../) package -- overview and installation diff --git a/docs/Reference/Contributed/TwinTimerPackage/index.md b/docs/Reference/Contributed/TwinTimerLib/index.md similarity index 56% rename from docs/Reference/Contributed/TwinTimerPackage/index.md rename to docs/Reference/Contributed/TwinTimerLib/index.md index 9077aa45..d4f082ef 100644 --- a/docs/Reference/Contributed/TwinTimerPackage/index.md +++ b/docs/Reference/Contributed/TwinTimerLib/index.md @@ -1,17 +1,17 @@ --- -title: TwinTimerPackage Package +title: TwinTimerLib Package parent: Contributed Packages has_toc: false -indexed_from: 1.0.0.0 -permalink: /tB/Packages/Contributed/TwinTimerPackage/ +indexed_from: 1.0.7.0 +permalink: /tB/Packages/Contributed/TwinTimerLib/ --- -# TwinTimerPackage Package +# TwinTimerLib Package {: .no_toc } **Author:** Krool -The **TwinTimerPackage** contributed package provides a Win32-backed timer class that fires a **Timer** event at a repeating interval and reports the total elapsed time in milliseconds. Unlike the built-in VB **Timer** control, **TwinTimer** does not require a form or control container and can be instantiated from any module. +The **TwinTimerLib** contributed package provides a Win32-backed timer class that fires a **Timer** event at a repeating interval and reports the total elapsed time in milliseconds. Unlike the built-in VB **Timer** control, **TwinTimer** does not require a form or control container and can be instantiated from any module. ## Classes diff --git a/docs/_book.yml b/docs/_book.yml index 16803381..0094470e 100644 --- a/docs/_book.yml +++ b/docs/_book.yml @@ -593,10 +593,10 @@ parts: landing_is_target: true outline_closed: true - - title: TwinTimerPackage Package + - title: TwinTimerLib Package subtitle: A Win32 timer class that reports the elapsed time - landing_page: /tB/Packages/Contributed/TwinTimerPackage/ - page: /tB/Packages/Contributed/TwinTimerPackage/ + landing_page: /tB/Packages/Contributed/TwinTimerLib/ + page: /tB/Packages/Contributed/TwinTimerLib/ landing_is_target: true outline_closed: true diff --git a/indexer/snapshots/contributed/TwinTimerPackage/api.json b/indexer/snapshots/contributed/TwinTimerLib/api.json similarity index 86% rename from indexer/snapshots/contributed/TwinTimerPackage/api.json rename to indexer/snapshots/contributed/TwinTimerLib/api.json index d75939c4..9eba6174 100644 --- a/indexer/snapshots/contributed/TwinTimerPackage/api.json +++ b/indexer/snapshots/contributed/TwinTimerLib/api.json @@ -1,8 +1,8 @@ { "format": 3, - "package": "TwinTimerPackage", - "project": "TwinTimerPackage", - "version": "1.0.0.0", + "package": "TwinTimerLib", + "project": "TwinTimerLib", + "version": "1.0.7.0", "types": [ { "name": "TwinTimer", @@ -17,18 +17,18 @@ {"name":"CreateTimer","kind":"sub","vis":"private","signature":"Private Sub CreateTimer()"}, {"name":"DestroyTimer","kind":"sub","vis":"private","signature":"Private Sub DestroyTimer()"}, {"name":"Enabled","kind":"property","vis":"public","signature":"Public Property Get Enabled() As Boolean","returnType":"Boolean","accessor":"Get"}, - {"name":"Enabled","kind":"property","vis":"public","signature":"Public Property Let Enabled(ByVal Value As Long)","accessor":"Let"}, + {"name":"Enabled","kind":"property","vis":"public","signature":"Public Property Let Enabled(ByVal Value As Boolean)","accessor":"Let"}, {"name":"GetTickCount","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function GetTickCount Lib \"kernel32\" () As Long","returnType":"Long"}, {"name":"Interval","kind":"property","vis":"public","signature":"Public Property Get Interval() As Long","returnType":"Long","accessor":"Get"}, {"name":"Interval","kind":"property","vis":"public","signature":"Public Property Let Interval(ByVal Value As Long)","accessor":"Let"}, - {"name":"KillTimer","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function KillTimer Lib \"user32\" (ByVal hWnd As LongPtr, ByVal nIDEvent As Long) As Long","returnType":"Long"}, + {"name":"KillTimer","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function KillTimer Lib \"user32\" (ByVal hWnd As LongPtr, ByVal nIDEvent As LongPtr) As Long","returnType":"Long"}, {"name":"PropEnabled","kind":"field","vis":"private","signature":"Private PropEnabled As Boolean"}, - {"name":"PropID","kind":"field","vis":"private","signature":"Private PropID As Long"}, + {"name":"PropID","kind":"field","vis":"private","signature":"Private PropID As LongPtr"}, {"name":"PropInterval","kind":"field","vis":"private","signature":"Private PropInterval As Long"}, {"name":"PropStartTime","kind":"field","vis":"private","signature":"Private PropStartTime As LongLong"}, - {"name":"SetTimer","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function SetTimer Lib \"user32\" (ByVal hWnd As LongPtr, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As Long","returnType":"Long"}, + {"name":"SetTimer","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function SetTimer Lib \"user32\" (ByVal hWnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr","returnType":"LongPtr"}, {"name":"Timer","kind":"event","vis":"public","signature":"Public Event Timer(ByVal ElapsedTime As LongLong)"}, - {"name":"TimerProc","kind":"sub","vis":"private","signature":"Private Sub TimerProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal nIDEvent As Long, ByVal dwTime As Long)"} + {"name":"TimerProc","kind":"sub","vis":"private","signature":"Private Sub TimerProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal nIDEvent As LongPtr, ByVal dwTime As Long)"} ] } ], diff --git a/test/example-projects/contributed-TwinTimerPackage/Settings b/test/example-projects/contributed-TwinTimerLib/Settings similarity index 90% rename from test/example-projects/contributed-TwinTimerPackage/Settings rename to test/example-projects/contributed-TwinTimerLib/Settings index 4f2f2c99..47cb9871 100644 --- a/test/example-projects/contributed-TwinTimerPackage/Settings +++ b/test/example-projects/contributed-TwinTimerLib/Settings @@ -51,14 +51,14 @@ "autoCtlExt": true, "id": "{8113CC0A-F2B5-4226-AF6D-C80883BD8138}", "licence": "MIT", - "name": "[IMPORTED] TwinTimer class for 32-bit and 64-bit", - "path32": "/Packages/TwinTimerPackage", - "path64": "/Packages/TwinTimerPackage", - "symbolId": "TwinTimerPackage", + "name": "[IMPORTED] TwinTimer Class for 32-bit and 64-bit", + "path32": "/Packages/TwinTimerLib", + "path64": "/Packages/TwinTimerLib", + "symbolId": "TwinTimerLib", "versionBuild": "0", "versionMajor": "1", "versionMinor": "0", - "versionRevision": "0" + "versionRevision": "7" } ], "project.settingsVersion": 1, From 243ac9dfadb6424f74f80efdf1ed95328e91527b Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:37:43 +0200 Subject: [PATCH 04/17] TBMANLIB_ListBoxHScroll: moved to 1.0.0.1, whose sources are those of 1.0.0.0 --- docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md | 2 +- .../snapshots/contributed/TBMANLIB_ListBoxHScroll/api.json | 2 +- .../contributed-TBMANLIB_ListBoxHScroll/Settings | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md b/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md index ccaa237e..2620f0fa 100644 --- a/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md +++ b/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md @@ -2,7 +2,7 @@ title: TBMANLIB_ListBoxHScroll Package parent: Contributed Packages has_toc: false -indexed_from: 1.0.0.0 +indexed_from: 1.0.0.1 permalink: /tB/Packages/Contributed/TBMANLIB_ListBoxHScroll/ --- diff --git a/indexer/snapshots/contributed/TBMANLIB_ListBoxHScroll/api.json b/indexer/snapshots/contributed/TBMANLIB_ListBoxHScroll/api.json index 5c881a49..1cde789d 100644 --- a/indexer/snapshots/contributed/TBMANLIB_ListBoxHScroll/api.json +++ b/indexer/snapshots/contributed/TBMANLIB_ListBoxHScroll/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "TBMANLIB_ListBoxHScroll", "project": "TBMANLIB_ListBoxHScroll", - "version": "1.0.0.0", + "version": "1.0.0.1", "types": [ { "name": "cListboxHScroll", diff --git a/test/example-projects/contributed-TBMANLIB_ListBoxHScroll/Settings b/test/example-projects/contributed-TBMANLIB_ListBoxHScroll/Settings index 7a3542a5..a3b4ce48 100644 --- a/test/example-projects/contributed-TBMANLIB_ListBoxHScroll/Settings +++ b/test/example-projects/contributed-TBMANLIB_ListBoxHScroll/Settings @@ -51,11 +51,11 @@ "autoCtlExt": true, "id": "{9DCDACC6-9E5C-4034-A93A-5D0335102C78}", "licence": "MIT", - "name": "[IMPORTED] TBMANLIB_ListBoxHScroll", + "name": "[IMPORTED] Horizontal scroll bar for Twinbasic ListBox control", "path32": "/Packages/TBMANLIB_ListBoxHScroll", "path64": "/Packages/TBMANLIB_ListBoxHScroll", "symbolId": "TBMANLIB_ListBoxHScroll", - "versionBuild": "0", + "versionBuild": "1", "versionMajor": "1", "versionMinor": "0", "versionRevision": "0" From 831bac438c0086b9be259f47c6d2847254b5bf7e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:37:56 +0200 Subject: [PATCH 05/17] TBMANLIB_Aes: moved to 1.0.0.4, whose sources are those of 1.0.0.2, so its defects stand --- docs/Reference/Contributed/TBMANLIB_Aes/cAes.md | 16 ++++++++-------- docs/Reference/Contributed/TBMANLIB_Aes/index.md | 8 ++++---- .../Contributed/TBMANLIB_Aes/mAesConstants.md | 4 ++-- docs/Reference/Experimental.md | 2 +- .../snapshots/contributed/TBMANLIB_Aes/api.json | 2 +- .../contributed-TBMANLIB_Aes/Settings | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/Reference/Contributed/TBMANLIB_Aes/cAes.md b/docs/Reference/Contributed/TBMANLIB_Aes/cAes.md index d42338f0..da9a50eb 100644 --- a/docs/Reference/Contributed/TBMANLIB_Aes/cAes.md +++ b/docs/Reference/Contributed/TBMANLIB_Aes/cAes.md @@ -62,7 +62,7 @@ Every call of an encrypt or a decrypt method starts again from **Key** and **IV* ## Which mode runs > [!WARNING] -> In version 1.0.0.2 the name of a mode is not always the mode that runs. **ECB** runs CBC with an IV of zero bytes, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV that the program sets, so the same key and plaintext always give the same ciphertext, and in the default mode **CBC** equal plaintext blocks give equal ciphertext blocks. A round trip succeeds in every case, because encryption and decryption use the same mode, so a test that only decrypts what it has encrypted shows nothing. +> In version 1.0.0.4 the name of a mode is not always the mode that runs. **ECB** runs CBC with an IV of zero bytes, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV that the program sets, so the same key and plaintext always give the same ciphertext, and in the default mode **CBC** equal plaintext blocks give equal ciphertext blocks. A round trip succeeds in every case, because encryption and decryption use the same mode, so a test that only decrypts what it has encrypted shows nothing. | Mode | Windows interface | What runs | The IV | |---|---|---|---| @@ -353,7 +353,7 @@ Debug.Print Err.Number A decryption with no tag set fails in the same way, after the line `DoDecryptCNG_GCM failed: GCM tag not set for decryption`. A tag of 16 bytes is the length that the encryption makes. The class passes the length of **GcmTag** to Windows as it is: a tag cut to its first 12 bytes is accepted and the decryption returns the plaintext, and one cut to 4 bytes makes Windows fail with an invalid parameter. > [!WARNING] -> In version 1.0.0.2, a GCM encryption with no IV set makes a random 12-byte nonce, uses it, and keeps it nowhere. [**IV**](#iv) stays empty. A decryption with no IV uses a nonce of 12 zero bytes, so its tag check fails and the data cannot be decrypted. The encryption raises no error. Set **IV** before every GCM encryption, and keep it with the ciphertext. +> In version 1.0.0.4, a GCM encryption with no IV set makes a random 12-byte nonce, uses it, and keeps it nowhere. [**IV**](#iv) stays empty. A decryption with no IV uses a nonce of 12 zero bytes, so its tag check fails and the data cannot be decrypted. The encryption raises no error. Set **IV** before every GCM encryption, and keep it with the ciphertext. ```tb check_build check_run projname=aes-class Dim aes As cAes = New cAes(AesKeySize.KeySize_128, AesCipherMode.GCM, AesPaddingMode.NoPadding) @@ -389,7 +389,7 @@ A failed call does not tell why, and what the caller gets depends on the member. > A program that calls **EncryptBytes** or **DecryptBytes** needs an `On Error` statement, and cannot tell a missing key from a wrong tag or a damaged ciphertext by the error. The Debug Console of the IDE shows more: the package prints lines with `Debug.Print`, such as `DecryptBytes error: Key not set` and `BCryptEncrypt failed: 0xC0000206` followed by a message, and a built program writes none of them. > [!WARNING] -> In version 1.0.0.2 the string members hide a failure in an empty string. **DecryptString** of a GCM message whose tag does not match, of a message with a wrong key in a mode with padding, and of Base64 text that is not valid, all give the same empty string as an empty plaintext would, and **EncryptString** gives an empty string for a missing key. A program must test the result with `Len`. +> In version 1.0.0.4 the string members hide a failure in an empty string. **DecryptString** of a GCM message whose tag does not match, of a message with a wrong key in a mode with padding, and of Base64 text that is not valid, all give the same empty string as an empty plaintext would, and **EncryptString** gives an empty string for a missing key. A program must test the result with `Len`. These are the causes of a failure in the source: @@ -456,7 +456,7 @@ The cipher mode. An [**AesCipherMode**](mAesConstants#aesciphermode) member, rea Syntax: *object*.**CipherMode** [ **=** *mode* ] -[Which mode runs](#which-mode-runs) says what each member does in version 1.0.0.2, and it differs from the names. The setter stores the value without a check, and sets [**IsInitialized**](#isinitialized) to **False**. A value that is not a member makes an encryption or a decryption fail. +[Which mode runs](#which-mode-runs) says what each member does in version 1.0.0.4, and it differs from the names. The setter stores the value without a check, and sets [**IsInitialized**](#isinitialized) to **False**. A value that is not a member makes an encryption or a decryption fail. ### GcmAAD {: .no_toc } @@ -645,7 +645,7 @@ With **NoPadding** in the modes **CFB**, **OFB**, **CTR** and **GCM**, the outpu **ISO10126** gives the output of **NoPadding**, and no padding is added. With **ZeroPadding** the decryption removes every zero byte at the end of the data, and with the data `41 42 00 00` it returns the two bytes `41 42`. > [!WARNING] -> With **ZeroPadding**, version 1.0.0.2 gives back less than it was given when the data ends in zero bytes. The decryption removes every zero byte at the end of the data, and not only the ones that the encryption added, and raises no error. Data that is all zero bytes fails the decryption. Use **PKCS7** for data that can end in zero bytes. +> With **ZeroPadding**, version 1.0.0.4 gives back less than it was given when the data ends in zero bytes. The decryption removes every zero byte at the end of the data, and not only the ones that the encryption added, and raises no error. Data that is all zero bytes fails the decryption. Use **PKCS7** for data that can end in zero bytes. ## Methods @@ -769,7 +769,7 @@ Syntax: *object*.**GenerateRandomIV** ( ) **As Byte()** Returns a **Byte** array of 16 bytes, which is also the new value of **IV**. The method calls `Randomize`, which mixes the system timer into the state of `Rnd` for the whole program, and then takes 16 values of `Rnd`. > [!WARNING] -> In version 1.0.0.2 the bytes come from `Rnd`, a pseudo-random generator, and not from a cryptographic one; the comment in the source says that the Crypto API would give better randomness. The state of `Rnd` has 24 bits: its sequence repeats after 16,777,216 values, so the method can return at most 16,777,216 different IVs, and two calls that start from the same state of `Rnd` return the same IV. A program that needs an IV that cannot be predicted can set [**IV**](#iv) from a source of its own. +> In version 1.0.0.4 the bytes come from `Rnd`, a pseudo-random generator, and not from a cryptographic one; the comment in the source says that the Crypto API would give better randomness. The state of `Rnd` has 24 bits: its sequence repeats after 16,777,216 values, so the method can return at most 16,777,216 different IVs, and two calls that start from the same state of `Rnd` return the same IV. A program that needs an IV that cannot be predicted can set [**IV**](#iv) from a source of its own. The first sample counts the calls of `Rnd` between a value and its next appearance. The second puts `Rnd` into the same state before each of two calls, with `Rnd -1` and `Randomize 7`, and finds two calls that return the same IV. @@ -839,7 +839,7 @@ Syntax: *object*.**SetGcmAADFromString** ( *aadString* [, *encoding*] ) The method does not raise an error. When the conversion fails, it prints `SetGcmAADFromString failed: ` and the description with `Debug.Print`, which a built program does not show, and leaves **GcmAAD** as it was. The program that decrypts has to convert the string in the same way, since the bytes with another encoding are other bytes. [**EncryptString**](#encryptstring) uses UTF-8 for its text, and this method does not. > [!WARNING] -> In version 1.0.0.2 an empty string does not remove the additional data. The method fails for an empty string and keeps the data that was set before, and only the Debug Console shows the message `SetGcmAADFromString failed: Unspecified error`. The next GCM encryption then authenticates the old data. To remove the data, assign an array that was never sized to [**GcmAAD**](#gcmaad). +> In version 1.0.0.4 an empty string does not remove the additional data. The method fails for an empty string and keeps the data that was set before, and only the Debug Console shows the message `SetGcmAADFromString failed: Unspecified error`. The next GCM encryption then authenticates the old data. To remove the data, assign an array that was never sized to [**GcmAAD**](#gcmaad). ```tb check_build check_run projname=aes-class Dim aes As New cAes @@ -873,7 +873,7 @@ Syntax: *object*.**SetKeyFromString** ( *keyString* [, *encoding*] ) The method converts *keyString* to bytes with **StrConv** and makes an array of the length that [**KeySize**](#keysize) names, 16, 24 or 32 bytes: the first bytes of the conversion when it is longer, and the bytes followed by zero bytes when it is shorter. The array is the new value of **Key**. The method does not use the string in any other way. > [!WARNING] -> In version 1.0.0.2 there is no key derivation. The key is the bytes of the text, cut or extended with zero bytes: a string longer than the key is cut without a message, so that two strings that begin with the same 32 bytes give the same key (with **KeySize_256**), and a short string is a short key followed by zeros. The modes **ECB** and **CBC** then hash the bytes once with SHA-256, without a salt; the modes **CFB**, **OFB**, **CTR** and **GCM** use them as the key. With the default encoding, a character that is not in the ANSI code page of the system is converted to another character, and the same text gives different bytes on systems with another code page. +> In version 1.0.0.4 there is no key derivation. The key is the bytes of the text, cut or extended with zero bytes: a string longer than the key is cut without a message, so that two strings that begin with the same 32 bytes give the same key (with **KeySize_256**), and a short string is a short key followed by zeros. The modes **ECB** and **CBC** then hash the bytes once with SHA-256, without a salt; the modes **CFB**, **OFB**, **CTR** and **GCM** use them as the key. With the default encoding, a character that is not in the ANSI code page of the system is converted to another character, and the same text gives different bytes on systems with another code page. The method raises an error when *keyString* is empty: **Err.Number** is `vbObjectError + 2`, **Err.Source** is `cAes.SetKeyFromString` and **Err.Description** is `Key cannot be empty`. **Key** is not changed, and [**IsInitialized**](#isinitialized) is set to **False**. When **KeySize** has a value that is not a member of the enumeration, the key is left as it was and no error is raised. diff --git a/docs/Reference/Contributed/TBMANLIB_Aes/index.md b/docs/Reference/Contributed/TBMANLIB_Aes/index.md index 542371b7..9a119220 100644 --- a/docs/Reference/Contributed/TBMANLIB_Aes/index.md +++ b/docs/Reference/Contributed/TBMANLIB_Aes/index.md @@ -6,7 +6,7 @@ exclude_from_docs: - mWin32CNG - mWin32CryptoAPI - mAesUsage -indexed_from: 1.0.0.2 +indexed_from: 1.0.0.4 permalink: /tB/Packages/Contributed/TBMANLIB_Aes/ --- @@ -15,7 +15,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_Aes/ **Author:** woeoio. -The **TBMANLIB_Aes** contributed package encrypts and decrypts text and byte arrays with AES. Its class [**cAes**](cAes) has six cipher modes, named ECB, CBC, CFB, OFB, CTR and GCM, four padding modes, and keys of 128, 192 and 256 bits. The package calls two interfaces of Windows. The older Crypto API (`advapi32.dll`) does the modes named ECB and CBC, and Cryptography API: Next Generation, CNG (`bcrypt.dll`), does the other four. A second class, [**cAesHelper**](cAesHelper), holds the Base64, UTF-8 and padding functions that **cAes** uses, and the module [**mAesConstants**](mAesConstants) holds the enumerations and the constants. This section documents version 1.0.0.2, published on TWINSERV under the MIT licence. The package describes itself as "TBMAN: A crypto library contains AES (ECB/CBC/CFB/OFB/CTR/GCM)". +The **TBMANLIB_Aes** contributed package encrypts and decrypts text and byte arrays with AES. Its class [**cAes**](cAes) has six cipher modes, named ECB, CBC, CFB, OFB, CTR and GCM, four padding modes, and keys of 128, 192 and 256 bits. The package calls two interfaces of Windows. The older Crypto API (`advapi32.dll`) does the modes named ECB and CBC, and Cryptography API: Next Generation, CNG (`bcrypt.dll`), does the other four. A second class, [**cAesHelper**](cAesHelper), holds the Base64, UTF-8 and padding functions that **cAes** uses, and the module [**mAesConstants**](mAesConstants) holds the enumerations and the constants. This section documents version 1.0.0.4, published on TWINSERV under the MIT licence. The package describes itself as "TBMAN: A crypto library contains AES (ECB/CBC/CFB/OFB/CTR/GCM)". Add the package to the project as [Importing a package from TWINSERV](../../../../Features/Packages/Importing-TWINSERV) describes. The classes are then created with `New`. @@ -42,7 +42,7 @@ Debug.Print aes.DecryptString(cipherText) ' Hello, AES! The text that **EncryptString** returns is Base64 of the ciphertext alone. The program keeps the IV, and in GCM mode the tag, and sets them in the object that decrypts. > [!WARNING] -> In version 1.0.0.2 the name of a cipher mode is not always the mode that runs: **ECB** runs CBC, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV, so the same key and plaintext always give the same ciphertext, and the default mode, **CBC**, gives equal ciphertext blocks for equal plaintext blocks. A test that decrypts what it has encrypted does not show this. [Known problems in version 1.0.0.2](#known-problems-in-version-1002) lists this and the other defects. +> In version 1.0.0.4 the name of a cipher mode is not always the mode that runs: **ECB** runs CBC, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV, so the same key and plaintext always give the same ciphertext, and the default mode, **CBC**, gives equal ciphertext blocks for equal plaintext blocks. A test that decrypts what it has encrypted does not show this. [Known problems in version 1.0.0.4](#known-problems-in-version-1004) lists this and the other defects. * TOC {:toc} @@ -56,7 +56,7 @@ The text that **EncryptString** returns is Base64 of the ciphertext alone. The p The conversion of text to Base64 and back uses `CryptBinaryToStringW` and `CryptStringToBinaryW` of `crypt32.dll`, and the conversion to UTF-8 and back uses `WideCharToMultiByte` and `MultiByteToWideChar` of `kernel32.dll`. The four CNG modes need CNG, which Windows has had since Windows Vista; the sources name Vista as the oldest version. -## Known problems in version 1.0.0.2 +## Known problems in version 1.0.0.4 - **The mode names.** **ECB** runs CBC with an IV of zero bytes, **CBC** runs ECB, **OFB** and **CTR** run CFB, and the CFB of the CNG modes has an 8-bit feedback. [Which mode runs](cAes#which-mode-runs) has the details and a sample for each. - **The key of ECB and CBC.** These modes hash [**Key**](cAes#key) with SHA-256 and use the hash as the AES key, and Windows adds its padding to the output. Other AES software that is given the same key does not decrypt it, and the standard test vectors of NIST SP 800-38A for ECB and CBC do not come out. See [The Crypto API modes](cAes#the-crypto-api-modes) and [Reading the output with other software](cAes#reading-the-output-with-other-software). diff --git a/docs/Reference/Contributed/TBMANLIB_Aes/mAesConstants.md b/docs/Reference/Contributed/TBMANLIB_Aes/mAesConstants.md index b579e848..84655834 100644 --- a/docs/Reference/Contributed/TBMANLIB_Aes/mAesConstants.md +++ b/docs/Reference/Contributed/TBMANLIB_Aes/mAesConstants.md @@ -41,7 +41,7 @@ The cipher mode that a [**cAes**](cAes) uses. Default: **CBC**. | **GCM** | 6 | CNG | GCM, with a 12-byte nonce and a 16-byte tag | > [!WARNING] -> In version 1.0.0.2 the name of a mode is not always the mode that runs. **ECB** runs CBC with an IV of zero bytes, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV that the program sets, so the same key and plaintext always give the same ciphertext, and the default mode, **CBC**, gives equal ciphertext blocks for equal plaintext blocks. Encryption and decryption agree with each other, so a round trip succeeds and shows nothing. [**cAes**](cAes#which-mode-runs) describes each mode in detail. +> In version 1.0.0.4 the name of a mode is not always the mode that runs. **ECB** runs CBC with an IV of zero bytes, **CBC** runs ECB, and **OFB** and **CTR** run CFB. Neither **ECB** nor **CBC** uses the IV that the program sets, so the same key and plaintext always give the same ciphertext, and the default mode, **CBC**, gives equal ciphertext blocks for equal plaintext blocks. Encryption and decryption agree with each other, so a round trip succeeds and shows nothing. [**cAes**](cAes#which-mode-runs) describes each mode in detail. The Crypto API is the older interface of Windows (`advapi32.dll`), and CNG, Cryptography API: Next Generation, the newer one (`bcrypt.dll`). **cAes** uses the Crypto API for **ECB** and **CBC**, and CNG for the other four modes. @@ -71,7 +71,7 @@ How [**cAes**](cAes) fills the last block of the data before it encrypts, and ho | **ISO10126** | 4 | Adds nothing, as **NoPadding**. | Takes nothing off, as **NoPadding**. | > [!WARNING] -> **ISO10126** is not implemented in version 1.0.0.2. It behaves as **NoPadding**, and no error says so. The comment in the source calls the member "ISO/IEC 7816-4 padding", a scheme that differs from ISO 10126, and neither is applied. +> **ISO10126** is not implemented in version 1.0.0.4. It behaves as **NoPadding**, and no error says so. The comment in the source calls the member "ISO/IEC 7816-4 padding", a scheme that differs from ISO 10126, and neither is applied. The functions that add and take off **PKCS7** and **ZeroPadding** padding are public members of [**cAesHelper**](cAesHelper). The padding of the data is only part of what the Crypto API modes do: Windows adds its own padding to the output of **ECB** and **CBC**, whatever the padding mode is. See [**PaddingMode**](cAes#paddingmode). diff --git a/docs/Reference/Experimental.md b/docs/Reference/Experimental.md index 801eb270..cc6a8864 100644 --- a/docs/Reference/Experimental.md +++ b/docs/Reference/Experimental.md @@ -15,7 +15,7 @@ These packages are published through TWINSERV, as the [Contributed Packages](../ - [**ArrayListLib**](../Contributed/ArrayListLib/) -- a list class in place of .NET's `ArrayList`. Version 1.4.0.134 does not compile in twinBASIC BETA 1005. - [**BigNumberLib**](../Contributed/BigNumberLib/) -- arbitrary-precision signed integer arithmetic. Version 0.0.0.0 does not compile in twinBASIC BETA 1005. - [**TBMANLIB**](../Contributed/TBMANLIB/) -- a toolkit of helpers: JSON, logs, INI files, strings, bytes, files and dictionaries. Version 1.0.0.5 compiles for 32-bit programs, crashes the compiler in a 64-bit build, and has several members that fail or give wrong results. -- [**TBMANLIB_Aes**](../Contributed/TBMANLIB_Aes/) -- AES encryption of text and byte arrays. Version 1.0.0.2 compiles, and its cipher modes are not the ones their names say: the default mode, CBC, runs ECB, and the output does not match the standard test vectors. +- [**TBMANLIB_Aes**](../Contributed/TBMANLIB_Aes/) -- AES encryption of text and byte arrays. Version 1.0.0.4 compiles, and its cipher modes are not the ones their names say: the default mode, CBC, runs ECB, and the output does not match the standard test vectors. - [**TBMANLIB_ConsoleComponents**](../Contributed/TBMANLIB_ConsoleComponents/) -- text-interface components for console programs: progress bars, charts, tables and panels. Version 0.0.0.0 compiles, and its components cannot use a console object of the published TBMANLIB_ConsoleCore. - [**TBMANLIB_ConsoleCore**](../Contributed/TBMANLIB_ConsoleCore/) -- a console library with colours, UTF-8 and a full-screen mode. Version 0.0.0.0 compiles, and it reads keys wrongly and has several helpers that give wrong results. - [**TBMANLIB_Diagnostic**](../Contributed/TBMANLIB_Diagnostic/) -- a diagnostic report of the computer and its processes, as text, JSON or HTML. Version 0.0.0.0 compiles, and its text report, its **Dictionary** class and several of its list and file helpers fail or give wrong results. diff --git a/indexer/snapshots/contributed/TBMANLIB_Aes/api.json b/indexer/snapshots/contributed/TBMANLIB_Aes/api.json index 30c245c4..e7cd0515 100644 --- a/indexer/snapshots/contributed/TBMANLIB_Aes/api.json +++ b/indexer/snapshots/contributed/TBMANLIB_Aes/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "TBMANLIB_Aes", "project": "TBMANLIB_Aes", - "version": "1.0.0.2", + "version": "1.0.0.4", "types": [ { "name": "cAes", diff --git a/test/example-projects/contributed-TBMANLIB_Aes/Settings b/test/example-projects/contributed-TBMANLIB_Aes/Settings index 83e41209..dd04becb 100644 --- a/test/example-projects/contributed-TBMANLIB_Aes/Settings +++ b/test/example-projects/contributed-TBMANLIB_Aes/Settings @@ -55,7 +55,7 @@ "path32": "/Packages/TBMANLIB_Aes", "path64": "/Packages/TBMANLIB_Aes", "symbolId": "TBMANLIB_Aes", - "versionBuild": "2", + "versionBuild": "4", "versionMajor": "1", "versionMinor": "0", "versionRevision": "0" From eb0aa4acb5344bdb5f2a3c75278e838b45562cbf Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:37:57 +0200 Subject: [PATCH 06/17] TBMANLIB_ConsoleCore: moved to 1.0.0.1, whose sources are those of 0.0.0.0 and which now declares the MIT licence --- .../Contributed/TBMANLIB_ConsoleCore/cConsole.md | 8 ++++---- .../Contributed/TBMANLIB_ConsoleCore/cConsoleBuffer.md | 4 ++-- docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md | 8 ++++---- .../Contributed/TBMANLIB_ConsoleCore/mConsoleStyle.md | 2 +- docs/Reference/Experimental.md | 2 +- .../snapshots/contributed/TBMANLIB_ConsoleCore/api.json | 2 +- .../contributed-TBMANLIB_ConsoleCore/Settings | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsole.md b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsole.md index 8154ab1a..72d1f4c8 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsole.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsole.md @@ -66,7 +66,7 @@ The class checks the result of two functions only. [**EnableVirtualTerminal**](# | [**ReadLine**](#readline) | An empty string, at once. | | [**KeyAvailable**](#keyavailable), [**PeekEvent**](#peekevent) | **False**, and an empty [**ConsoleKeyInfo**](Types#consolekeyinfo). | | [**ReadKeyTimeout**](#readkeytimeout) | Returns the empty structure when the time is over. | -| [**ReadKey**](#readkey), [**ReadPassword**](#readpassword) | Do not return; see [Known problems](#known-problems-in-version-0000). | +| [**ReadKey**](#readkey), [**ReadPassword**](#readpassword) | Do not return; see [Known problems](#known-problems-in-version-1001). | | [**EnterFullScreenMode**](#enterfullscreenmode) | Creates the 80 by 25 [**cConsoleBuffer**](cConsoleBuffer); [**Refresh**](#refresh) writes nothing. | | [**IsKeyPressed**](#iskeypressed) | Works, since it does not use the console. | @@ -80,10 +80,10 @@ A program that must work with redirected output writes with `WriteFile` in that With the input read from the null device or from a file, [**ReadLine**](#readline) returns an empty string at once and [**KeyAvailable**](#keyavailable) is **False**. [**ReadKey**](#readkey) does not return. -## Known problems in version 0.0.0.0 +## Known problems in version 1.0.0.1 > [!WARNING] -> In version 0.0.0.0, [**ReadKey**](#readkey) and [**ReadPassword**](#readpassword) never return when the program has no console input: `ReadKey` loops until `ReadConsoleInputW` delivers a key-down event, and the call fails at once when the program has no console or its input is not a console. A comparison of a key with a member of the [**ConsoleKey**](Types#consolekey) enumeration is true for the wrong key and raises no error: [**KeyCode**](Types#consolekeyinfo) holds Windows virtual-key codes, but the arrow, navigation and function keys of **ConsoleKey** have other values, so `keyInfo.KeyCode = ConsoleKey.KeyUp` is false for the Up Arrow key (38) and true for the H key (72). +> In version 1.0.0.1, [**ReadKey**](#readkey) and [**ReadPassword**](#readpassword) never return when the program has no console input: `ReadKey` loops until `ReadConsoleInputW` delivers a key-down event, and the call fails at once when the program has no console or its input is not a console. A comparison of a key with a member of the [**ConsoleKey**](Types#consolekey) enumeration is true for the wrong key and raises no error: [**KeyCode**](Types#consolekeyinfo) holds Windows virtual-key codes, but the arrow, navigation and function keys of **ConsoleKey** have other values, so `keyInfo.KeyCode = ConsoleKey.KeyUp` is false for the Up Arrow key (38) and true for the H key (72). - **KeyAvailable and the key-up events.** [**KeyAvailable**](#keyavailable) is true while the input queue holds any event, including the event for a key that was released, so a loop that tests it and then calls [**ReadKey**](#readkey) can block in **ReadKey** until the next key press. - **The colours of the Write members.** [**WriteColored**](#writecolored), [**WriteLineColored**](#writelinecolored) and [**WriteAtColored**](#writeatcolored) use a black background unless one is given, and put back the colours that the object tracks, which are Gray on Black until a property sets others, and not the colours that the console had. @@ -688,7 +688,7 @@ Returns a [**ConsoleKeyInfo**](Types#consolekeyinfo) for the first key-down even While it waits, the method sets the input mode to 0 and puts the old mode back before it returns. With no mode flags the console does not echo the key, does not edit a line, and does not turn Ctrl+C into an interruption. When *intercept* is **False** the method writes **KeyChar** itself with [**WriteTo**](#writeto), even when it is the character with code 0. -Calls `GetConsoleMode`, `SetConsoleMode` (twice) and `ReadConsoleInputW`. Without a console, or with the input redirected, `ReadConsoleInputW` fails at once and the method never returns; see [Known problems](#known-problems-in-version-0000). +Calls `GetConsoleMode`, `SetConsoleMode` (twice) and `ReadConsoleInputW`. Without a console, or with the input redirected, `ReadConsoleInputW` fails at once and the method never returns; see [Known problems](#known-problems-in-version-1001). ```tb check_build Dim con As New cConsole diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsoleBuffer.md b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsoleBuffer.md index e074e778..40a697d2 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsoleBuffer.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/cConsoleBuffer.md @@ -87,10 +87,10 @@ Debug.Print r.Left & " " & r.Top & " " & r.Right & " " & r.Bottom ' 0 0 9 2 ``` -## Known problems in version 0.0.0.0 +## Known problems in version 1.0.0.1 > [!WARNING] -> In version 0.0.0.0, [**ScrollRegion**](#scrollregion) moves a region by less than the distance asked for when the region starts closer to the top or left edge than that distance, and clears the full distance, so cells are lost without an error. A [**WriteAt**](#writeat), [**FillRect**](#fillrect) or [**CopyRegion**](#copyregion) with a negative column or row makes the next [**Flush**](#flush) draw nothing, and raises no error; see [The dirty rectangle](#the-dirty-rectangle). +> In version 1.0.0.1, [**ScrollRegion**](#scrollregion) moves a region by less than the distance asked for when the region starts closer to the top or left edge than that distance, and clears the full distance, so cells are lost without an error. A [**WriteAt**](#writeat), [**FillRect**](#fillrect) or [**CopyRegion**](#copyregion) with a negative column or row makes the next [**Flush**](#flush) draw nothing, and raises no error; see [The dirty rectangle](#the-dirty-rectangle). ## Constructor diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md index 57dc01c6..5af82300 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md @@ -4,7 +4,7 @@ parent: Experimental Packages has_toc: false exclude_from_docs: - mConsoleAPI -indexed_from: 0.0.0.0 +indexed_from: 1.0.0.1 permalink: /tB/Packages/Contributed/TBMANLIB_ConsoleCore/ --- @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_ConsoleCore/ **Author:** woeoio. -The **TBMANLIB_ConsoleCore** contributed package is a library for the console of a twinBASIC program. Its class [**cConsole**](cConsole) writes text in 16 colours, reads lines, single keys and passwords, moves the cursor, switches the console to UTF-8 and to the escape-sequence mode, and has a full-screen mode in which a program draws into an in-memory grid, [**cConsoleBuffer**](cConsoleBuffer), and receives key, mouse and window-size events. The module [**mConsoleStyle**](mConsoleStyle) builds the escape sequences for colours, text styles and cursor movement, and has helpers that align, shorten and wrap text. This section documents version 0.0.0.0, published on TWINSERV on 1 February 2026 with no licence declared. The package describes itself as "TBMAN: Modern console library with UTF-8, colors, and full-screen support". +The **TBMANLIB_ConsoleCore** contributed package is a library for the console of a twinBASIC program. Its class [**cConsole**](cConsole) writes text in 16 colours, reads lines, single keys and passwords, moves the cursor, switches the console to UTF-8 and to the escape-sequence mode, and has a full-screen mode in which a program draws into an in-memory grid, [**cConsoleBuffer**](cConsoleBuffer), and receives key, mouse and window-size events. The module [**mConsoleStyle**](mConsoleStyle) builds the escape sequences for colours, text styles and cursor movement, and has helpers that align, shorten and wrap text. This section documents version 1.0.0.1, published on TWINSERV on 3 February 2026 under the MIT licence. The package describes itself as "TBMAN: Modern console library with UTF-8, colors, and full-screen support". The library is built on the Windows console functions of `kernel32.dll`. The package [TBMANLIB_ConsoleComponents](../TBMANLIB_ConsoleComponents/), by the same author, is a set of text-interface components that draw into the buffer of this package. @@ -33,7 +33,7 @@ con.Restore ``` > [!WARNING] -> Several members of version 0.0.0.0 do not do what their names suggest. [**ReadKey**](cConsole#readkey) never returns in a program that has no console input, and a comparison of a key with a member of [**ConsoleKey**](Types#consolekey) is true for the wrong key. [Defects in version 0.0.0.0](#defects-in-version-0000) lists them with the pages that describe them. +> Several members of version 1.0.0.1 do not do what their names suggest. [**ReadKey**](cConsole#readkey) never returns in a program that has no console input, and a comparison of a key with a member of [**ConsoleKey**](Types#consolekey) is true for the wrong key. [Defects in version 1.0.0.1](#defects-in-version-1001) lists them with the pages that describe them. * TOC {:toc} @@ -53,7 +53,7 @@ A program with no console can create a **cConsole**, and the buffer of the full- - **The buffer.** [**cConsoleBuffer**](cConsoleBuffer) draws characters, lines, boxes and filled rectangles, copies and scrolls regions, and keeps a dirty rectangle so that [**Flush**](cConsoleBuffer#flush) writes only what changed. - **Escape sequences.** [**mConsoleStyle**](mConsoleStyle) returns the sequences for 16, 256 and 24-bit colours, bold, underline and the other styles, cursor movement, clearing, scrolling and the alternate screen, and constants for box-drawing, block, arrow and symbol characters. -## Defects in version 0.0.0.0 +## Defects in version 1.0.0.1 - [**ReadKey**](cConsole#readkey) and [**ReadPassword**](cConsole#readpassword) never return when the program has no console input. - The key codes of [**ConsoleKey**](Types#consolekey) are not the virtual-key codes that [**ReadKey**](cConsole#readkey) and the key handler return, except for Enter, Escape, Space, Backspace and Tab. diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/mConsoleStyle.md b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/mConsoleStyle.md index 4ba149e9..146b415b 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/mConsoleStyle.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/mConsoleStyle.md @@ -44,7 +44,7 @@ End If con.Restore ``` -## Known problems in version 0.0.0.0 +## Known problems in version 1.0.0.1 - [**RepeatStr**](#repeatstr) repeats the first character of its string, not the string. - [**StripAnsi**](#stripansi) ends a sequence only at one of eight letters, so it also removes the text after the sequences that end in another letter, such as the one made by **CursorHide**. diff --git a/docs/Reference/Experimental.md b/docs/Reference/Experimental.md index cc6a8864..c327a359 100644 --- a/docs/Reference/Experimental.md +++ b/docs/Reference/Experimental.md @@ -17,7 +17,7 @@ These packages are published through TWINSERV, as the [Contributed Packages](../ - [**TBMANLIB**](../Contributed/TBMANLIB/) -- a toolkit of helpers: JSON, logs, INI files, strings, bytes, files and dictionaries. Version 1.0.0.5 compiles for 32-bit programs, crashes the compiler in a 64-bit build, and has several members that fail or give wrong results. - [**TBMANLIB_Aes**](../Contributed/TBMANLIB_Aes/) -- AES encryption of text and byte arrays. Version 1.0.0.4 compiles, and its cipher modes are not the ones their names say: the default mode, CBC, runs ECB, and the output does not match the standard test vectors. - [**TBMANLIB_ConsoleComponents**](../Contributed/TBMANLIB_ConsoleComponents/) -- text-interface components for console programs: progress bars, charts, tables and panels. Version 0.0.0.0 compiles, and its components cannot use a console object of the published TBMANLIB_ConsoleCore. -- [**TBMANLIB_ConsoleCore**](../Contributed/TBMANLIB_ConsoleCore/) -- a console library with colours, UTF-8 and a full-screen mode. Version 0.0.0.0 compiles, and it reads keys wrongly and has several helpers that give wrong results. +- [**TBMANLIB_ConsoleCore**](../Contributed/TBMANLIB_ConsoleCore/) -- a console library with colours, UTF-8 and a full-screen mode. Version 1.0.0.1 compiles, and it reads keys wrongly and has several helpers that give wrong results. - [**TBMANLIB_Diagnostic**](../Contributed/TBMANLIB_Diagnostic/) -- a diagnostic report of the computer and its processes, as text, JSON or HTML. Version 0.0.0.0 compiles, and its text report, its **Dictionary** class and several of its list and file helpers fail or give wrong results. - [**TBMANLIB_Xml**](../Contributed/TBMANLIB_Xml/) -- XML documents parsed, edited and written, in twinBASIC code. Version 1.0.0.0 compiles, and its parser misreads some common XML, such as self-closing elements and entities in text, and does not return for some malformed text. - [**WinReg**](../Contributed/WinReg/) -- registry keys and values, read, written, deleted and enumerated. Version 0.0.0.0 does not compile in twinBASIC BETA 1005. diff --git a/indexer/snapshots/contributed/TBMANLIB_ConsoleCore/api.json b/indexer/snapshots/contributed/TBMANLIB_ConsoleCore/api.json index 901e8132..c2257ff9 100644 --- a/indexer/snapshots/contributed/TBMANLIB_ConsoleCore/api.json +++ b/indexer/snapshots/contributed/TBMANLIB_ConsoleCore/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "TBMANLIB_ConsoleCore", "project": "TBMANLIB_ConsoleCore", - "version": "0.0.0.0", + "version": "1.0.0.1", "types": [ { "name": "cConsole", diff --git a/test/example-projects/contributed-TBMANLIB_ConsoleCore/Settings b/test/example-projects/contributed-TBMANLIB_ConsoleCore/Settings index f81f3de7..d17eee02 100644 --- a/test/example-projects/contributed-TBMANLIB_ConsoleCore/Settings +++ b/test/example-projects/contributed-TBMANLIB_ConsoleCore/Settings @@ -55,8 +55,8 @@ "path32": "/Packages/TBMANLIB_ConsoleCore", "path64": "/Packages/TBMANLIB_ConsoleCore", "symbolId": "TBMANLIB_ConsoleCore", - "versionBuild": "0", - "versionMajor": "0", + "versionBuild": "1", + "versionMajor": "1", "versionMinor": "0", "versionRevision": "0" } From cca38592eef596da05f8136507a02b3efb46fee5 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:37:59 +0200 Subject: [PATCH 07/17] VBA_JSON: moved to 2.3.1.1, whose Dictionary.Item takes its key ByVal, so a Variant key needs no CStr --- docs/Reference/Contributed/VBA_JSON/Dictionary/Keys.md | 2 +- docs/Reference/Contributed/VBA_JSON/Dictionary/index.md | 6 +++--- docs/Reference/Contributed/VBA_JSON/index.md | 2 +- indexer/snapshots/contributed/VBA_JSON/api.json | 8 ++++---- test/example-projects/contributed-VBA_JSON/Settings | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/Reference/Contributed/VBA_JSON/Dictionary/Keys.md b/docs/Reference/Contributed/VBA_JSON/Dictionary/Keys.md index d4f9f785..4f2e578c 100644 --- a/docs/Reference/Contributed/VBA_JSON/Dictionary/Keys.md +++ b/docs/Reference/Contributed/VBA_JSON/Dictionary/Keys.md @@ -28,7 +28,7 @@ Dict("age") = 30 Dim k As Variant For Each k In Dict.Keys - Debug.Print k & " => " & Dict(CStr(k)) + Debug.Print k & " => " & Dict(k) Next k ' Output (order added): ' name => Alice diff --git a/docs/Reference/Contributed/VBA_JSON/Dictionary/index.md b/docs/Reference/Contributed/VBA_JSON/Dictionary/index.md index 5aa353bf..b52f5071 100644 --- a/docs/Reference/Contributed/VBA_JSON/Dictionary/index.md +++ b/docs/Reference/Contributed/VBA_JSON/Dictionary/index.md @@ -76,11 +76,11 @@ d("y") = 2 Dim k As Variant For Each k In d.Keys - Debug.Print k & " = " & d(CStr(k)) + Debug.Print k & " = " & d(k) Next ``` -**Item** takes its key `ByRef` as a **String**, so a key held in a **Variant**, such as the loop variable of a **For Each** over **Keys**, is passed through **CStr**: passing the **Variant** itself is a compile error. +**Item** takes its key `ByVal` as a **String**, so a key held in a **Variant**, such as the loop variable of a **For Each** over **Keys**, is converted to a **String** when it is passed. ## Remarks @@ -126,7 +126,7 @@ Debug.Print parsed("score") ' 95 Dim k As Variant For Each k In parsed.Keys - Debug.Print k & ": " & parsed(CStr(k)) + Debug.Print k & ": " & parsed(k) Next ``` diff --git a/docs/Reference/Contributed/VBA_JSON/index.md b/docs/Reference/Contributed/VBA_JSON/index.md index d6b4dc86..b9ea94cb 100644 --- a/docs/Reference/Contributed/VBA_JSON/index.md +++ b/docs/Reference/Contributed/VBA_JSON/index.md @@ -2,7 +2,7 @@ title: VBA_JSON Package parent: Contributed Packages has_toc: false -indexed_from: 2.3.0.1 +indexed_from: 2.3.1.1 permalink: /tB/Packages/Contributed/VBA_JSON/ --- diff --git a/indexer/snapshots/contributed/VBA_JSON/api.json b/indexer/snapshots/contributed/VBA_JSON/api.json index 057cc886..abd6d28a 100644 --- a/indexer/snapshots/contributed/VBA_JSON/api.json +++ b/indexer/snapshots/contributed/VBA_JSON/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "VBA_JSON", "project": "VBA_JSON", - "version": "2.3.0.1", + "version": "2.3.1.1", "types": [ { "name": "Dictionary", @@ -12,9 +12,9 @@ "signature": "Public Class Dictionary", "attrs": [{"name":"ClassId","args":"\"6DB2FF1D-F9BE-4C3E-9D7F-515E46E36EAC\""},{"name":"InterfaceId","args":"\"217032FB-B259-4633-BED0-34C7C21DF57E\""}], "members": [ - {"name":"Item","kind":"property","vis":"public","signature":"Public Property Get Item(Key As String) As Variant","returnType":"Variant","accessor":"Get","attrs":[{"name":"DefaultMember"}]}, - {"name":"Item","kind":"property","vis":"public","signature":"Public Property Let Item(Key As String, Value As Variant)","accessor":"Let"}, - {"name":"Item","kind":"property","vis":"public","signature":"Public Property Set Item(Key As String, Value As Variant)","accessor":"Set"}, + {"name":"Item","kind":"property","vis":"public","signature":"Public Property Get Item(ByVal Key As String) As Variant","returnType":"Variant","accessor":"Get","attrs":[{"name":"DefaultMember"}]}, + {"name":"Item","kind":"property","vis":"public","signature":"Public Property Let Item(ByVal Key As String, Value As Variant)","accessor":"Let"}, + {"name":"Item","kind":"property","vis":"public","signature":"Public Property Set Item(ByVal Key As String, Value As Variant)","accessor":"Set"}, {"name":"Keys","kind":"property","vis":"public","signature":"Public Property Get Keys() As Variant","returnType":"Variant","accessor":"Get"}, {"name":"_NewEnum","kind":"function","vis":"private","signature":"Private Function _NewEnum() As Variant","returnType":"Variant","attrs":[{"name":"Enumerator"}]}, {"name":"m_Collection","kind":"field","vis":"private","signature":"Private m_Collection As Collection = New Collection"} diff --git a/test/example-projects/contributed-VBA_JSON/Settings b/test/example-projects/contributed-VBA_JSON/Settings index a258d56f..6e348dc9 100644 --- a/test/example-projects/contributed-VBA_JSON/Settings +++ b/test/example-projects/contributed-VBA_JSON/Settings @@ -58,7 +58,7 @@ "versionBuild": "1", "versionMajor": "2", "versionMinor": "3", - "versionRevision": "0" + "versionRevision": "1" } ], "project.settingsVersion": 1, From a3a0157842b78c8607fb7c6b16b09433b4d03c3d Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:40:14 +0200 Subject: [PATCH 08/17] Contributed landing pages: the version each section documents, its indexed_from, next to the author (owner); the draft workflow writes it --- WIP.md | 2 +- docs/Reference/Contributed/ArrayListLib/index.md | 2 +- docs/Reference/Contributed/AutoCompleteLib/index.md | 2 +- docs/Reference/Contributed/BigNumberLib/index.md | 2 +- docs/Reference/Contributed/FileProps/index.md | 2 +- docs/Reference/Contributed/Fmt/index.md | 2 +- docs/Reference/Contributed/Generics/index.md | 2 +- docs/Reference/Contributed/OLEGuids/index.md | 2 +- docs/Reference/Contributed/TBMANLIB/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_Aes/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_ConsoleComponents/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_Diagnostic/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_Dialog/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_RES/index.md | 2 +- docs/Reference/Contributed/TBMANLIB_Xml/index.md | 2 +- docs/Reference/Contributed/TwinTimerLib/index.md | 2 +- docs/Reference/Contributed/VBA_JSON/index.md | 2 +- docs/Reference/Contributed/VBComDlg/index.md | 2 +- docs/Reference/Contributed/WinReg/index.md | 2 +- docs/Reference/Contributed/tbFileSysTools/index.md | 2 +- docs/Reference/Contributed/tbProjPacker/index.md | 2 +- docs/Reference/Contributed/tbRegExp/index.md | 2 +- docs/Reference/Contributed/tsJson/index.md | 2 +- docs/Reference/Contributed/tsPwGen/index.md | 2 +- docs/Reference/Contributed/xCalendar/index.md | 2 +- indexer/draft/workflow.mjs | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/WIP.md b/WIP.md index 6fe57c36..8e29b878 100644 --- a/WIP.md +++ b/WIP.md @@ -79,7 +79,7 @@ The rest of this file is the maintenance guide for updating existing pages or ad > would file the page as a *static file* and serve the raw markdown. Editors on > Windows add a BOM unasked. `lib/frontmatter.mjs` strips a leading BOM before parsing. - `docs/Reference/Built-In/tbIDE/` — IDE Extensibility package (this is the **addin SDK**). The package is type-only — it ships **public interfaces + CoClasses** that an addin DLL binds to; every implementation behind them lives in the twinBASIC IDE itself. The user-facing surface is one entry-point factory (`tbCreateCompilerAddin`) plus 23 CoClasses grouped by role: the addin contract (`AddIn`), the root API (`Host`), the loaded `Project`, the editors collection (`Editor` / `CodeEditor` / `Editors`), the virtual file system (`FileSystem` / `FileSystemItem` / `Folder` / `File`), the in-IDE UI surface (`Toolbar` / `Toolbars` / `Button` / `ToolWindow` / `ToolWindows`), the HTML DOM inside a tool window (`HtmlElement` / `HtmlElements` / `HtmlElementProperty` / `HtmlElementProperties` / `HtmlEventProperty` / `HtmlEventProperties`), the `DebugConsole`, `KeyboardShortcuts`, `Themes`, and the single concrete user-instantiable helper class `AddinTimer`. Flat layout — one page per CoClass / Class plus the index landing. -- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. +- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner, 2026-10-12). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. - `docs/Reference/Statements.md` — alphabetical index of language statements. - `docs/Reference/Procedures and Functions.md` — alphabetical index of procedures/functions. - `docs/LLVM/` — the LLVM section: compiling with the LLVM back end. A top-level section between Features and Reference Section in the nav, at `nav_order: 6` (Features is 5). `index.md` is the landing page and `Getting-Started.md` the only page so far, with its screenshots under `Images/`. Everything it describes arrived in **BETA 984**. Its language claims are measured on BETA 995 with `tbrun --llvm` and `--exe`: the comma, space and comma-space spellings of `[CompilerOptions]` all turn LLVM and `+optimize` on, `[CompilerOptions("")]` turns it off under project-wide LLVM, the long CPU-flag sample runs, and an error is lost between procedures when either the callee or the caller is LLVM-compiled. Its samples are marked `check_build`, which compiles them; `examples.bat --llvm` also builds them with LLVM. diff --git a/docs/Reference/Contributed/ArrayListLib/index.md b/docs/Reference/Contributed/ArrayListLib/index.md index c2898f06..db6a5aa9 100644 --- a/docs/Reference/Contributed/ArrayListLib/index.md +++ b/docs/Reference/Contributed/ArrayListLib/index.md @@ -12,7 +12,7 @@ permalink: /tB/Packages/Contributed/ArrayListLib/ # ArrayListLib Package {: .no_toc } -**Author:** R.Beltran. **On GitHub:** [Theadd/ArrayList](https://github.com/Theadd/ArrayList), in the folder *ArrayListLib*. +**Author:** R.Beltran. **Version:** 1.4.0.134. **On GitHub:** [Theadd/ArrayList](https://github.com/Theadd/ArrayList), in the folder *ArrayListLib*. The **ArrayListLib** contributed package is a list class for twinBASIC, in place of the `ArrayList` class of .NET's `mscorlib` library. A VBA or VB6 program that needs a list which grows as items are added can use that class through `CreateObject("System.Collections.ArrayList")`. [**ArrayList**](ArrayList) has the members of that class which a COM client can call, under the same names, and needs no .NET Framework. diff --git a/docs/Reference/Contributed/AutoCompleteLib/index.md b/docs/Reference/Contributed/AutoCompleteLib/index.md index 3035f885..12ef05d6 100644 --- a/docs/Reference/Contributed/AutoCompleteLib/index.md +++ b/docs/Reference/Contributed/AutoCompleteLib/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/AutoCompleteLib/ # AutoCompleteLib Package {: .no_toc } -**Author:** Krool +**Author:** Krool. **Version:** 1.0.0.0 The **AutoCompleteLib** contributed package provides Windows shell auto-complete behavior for text-input controls. The package references the **AutoCompleteGuids** package, which holds the GUID and interface definitions the class uses. diff --git a/docs/Reference/Contributed/BigNumberLib/index.md b/docs/Reference/Contributed/BigNumberLib/index.md index 3f3c865c..0897d9c5 100644 --- a/docs/Reference/Contributed/BigNumberLib/index.md +++ b/docs/Reference/Contributed/BigNumberLib/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/BigNumberLib/ # BigNumberLib Package {: .no_toc } -**Author:** WaynePhillipsEA +**Author:** WaynePhillipsEA. **Version:** 0.0.0.0 The **BigNumberLib** contributed package provides arbitrary-precision signed integer arithmetic for twinBASIC. diff --git a/docs/Reference/Contributed/FileProps/index.md b/docs/Reference/Contributed/FileProps/index.md index ff8d2b40..e77eda30 100644 --- a/docs/Reference/Contributed/FileProps/index.md +++ b/docs/Reference/Contributed/FileProps/index.md @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/FileProps/ # FileProps Package {: .no_toc } -**Author:** WaynePhillipsEA +**Author:** WaynePhillipsEA. **Version:** 1.7.1.0 The **FileProps** contributed package provides access to Windows shell file properties through a Virtual-COM wrapper. It exposes a predeclared **FilePropertyExplorer** class that opens a file and returns a **FileProperties** collection; each entry in that collection is a **FileProperty** object with the system name, localized name, unique ID, and current value of one shell property. diff --git a/docs/Reference/Contributed/Fmt/index.md b/docs/Reference/Contributed/Fmt/index.md index 86986a74..5d888cb0 100644 --- a/docs/Reference/Contributed/Fmt/index.md +++ b/docs/Reference/Contributed/Fmt/index.md @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/Fmt/ # Fmt Package {: .no_toc } -**Author:** FullValueRider +**Author:** FullValueRider. **Version:** 1.0.0.0 The **Fmt** contributed package provides [**StringFormat**](PublicEntryPoints/StringFormat), a function that builds a string from a format string and a list of values, in the style of C#'s **String.Format**. A format string holds text, format items such as `{0}`, `{1,8}` or `{2:F2}`, and C-style escape sequences such as `\n` and `\q`. Each format item is replaced by the value at its index, formatted and padded as the item says. diff --git a/docs/Reference/Contributed/Generics/index.md b/docs/Reference/Contributed/Generics/index.md index 23970319..65ba29ff 100644 --- a/docs/Reference/Contributed/Generics/index.md +++ b/docs/Reference/Contributed/Generics/index.md @@ -11,7 +11,7 @@ permalink: /tB/Packages/Contributed/Generics/ # Generics Package {: .no_toc } -**Author:** mansellan. +**Author:** mansellan. **Version:** 1.0.0.0 The **Generics** contributed package provides seven tuple classes, **TupleOf1** to **TupleOf7**. A tuple is a read-only object that holds one to seven values, called its items, each of a type given when the tuple is declared. diff --git a/docs/Reference/Contributed/OLEGuids/index.md b/docs/Reference/Contributed/OLEGuids/index.md index 7a94f147..56956b08 100644 --- a/docs/Reference/Contributed/OLEGuids/index.md +++ b/docs/Reference/Contributed/OLEGuids/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/OLEGuids/ # OLEGuids Package {: .no_toc } -**Author:** Krool. **On GitHub:** [Kr00l/VBCCR](https://github.com/Kr00l/VBCCR/tree/master/twinBASIC%20Package/OLEGuids), in the folder *twinBASIC Package/OLEGuids*. +**Author:** Krool. **Version:** 1.0.2.0. **On GitHub:** [Kr00l/VBCCR](https://github.com/Kr00l/VBCCR/tree/master/twinBASIC%20Package/OLEGuids), in the folder *twinBASIC Package/OLEGuids*. A twinBASIC package that declares 23 OLE and COM interfaces and 10 structures in twinBASIC source, so that a 32-bit or 64-bit project can call or implement them without a type library. diff --git a/docs/Reference/Contributed/TBMANLIB/index.md b/docs/Reference/Contributed/TBMANLIB/index.md index c67fccf1..e34e15cd 100644 --- a/docs/Reference/Contributed/TBMANLIB/index.md +++ b/docs/Reference/Contributed/TBMANLIB/index.md @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB/ # TBMANLIB Package {: .no_toc } -**Author:** woeoio. **On GitHub:** [woeoio/tbman](https://github.com/woeoio/tbman), the repository of the TBMAN toolkit. Its first commit, of 7 December 2024, the day this version was published, holds the code of this package. The repository has been developed since, and its current code differs from version 1.0.0.5. +**Author:** woeoio. **Version:** 1.0.0.5. **On GitHub:** [woeoio/tbman](https://github.com/woeoio/tbman), the repository of the TBMAN toolkit. Its first commit, of 7 December 2024, the day this version was published, holds the code of this package. The repository has been developed since, and its current code differs from version 1.0.0.5. The **TBMANLIB** contributed package is the library of **TBMAN**, a toolkit for twinBASIC programmers that grew out of the author's VB6 library *vbman*. It is a collection of small helpers rather than a library with one theme: a JSON document class and parser, a log writer, a stopwatch, an INI file class, a message-box helper, and modules of functions for strings, arrays and bytes, UTF-8, dictionaries, files and folders, numbers and JavaScript objects. The package's own description on TWINSERV is the single word *TBMAN*. diff --git a/docs/Reference/Contributed/TBMANLIB_Aes/index.md b/docs/Reference/Contributed/TBMANLIB_Aes/index.md index 9a119220..71636d23 100644 --- a/docs/Reference/Contributed/TBMANLIB_Aes/index.md +++ b/docs/Reference/Contributed/TBMANLIB_Aes/index.md @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_Aes/ # TBMANLIB_Aes Package {: .no_toc } -**Author:** woeoio. +**Author:** woeoio. **Version:** 1.0.0.4 The **TBMANLIB_Aes** contributed package encrypts and decrypts text and byte arrays with AES. Its class [**cAes**](cAes) has six cipher modes, named ECB, CBC, CFB, OFB, CTR and GCM, four padding modes, and keys of 128, 192 and 256 bits. The package calls two interfaces of Windows. The older Crypto API (`advapi32.dll`) does the modes named ECB and CBC, and Cryptography API: Next Generation, CNG (`bcrypt.dll`), does the other four. A second class, [**cAesHelper**](cAesHelper), holds the Base64, UTF-8 and padding functions that **cAes** uses, and the module [**mAesConstants**](mAesConstants) holds the enumerations and the constants. This section documents version 1.0.0.4, published on TWINSERV under the MIT licence. The package describes itself as "TBMAN: A crypto library contains AES (ECB/CBC/CFB/OFB/CTR/GCM)". diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleComponents/index.md b/docs/Reference/Contributed/TBMANLIB_ConsoleComponents/index.md index 3cfb8162..3d00e4b7 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleComponents/index.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleComponents/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_ConsoleComponents/ # TBMANLIB_ConsoleComponents Package {: .no_toc } -**Author:** woeoio. +**Author:** woeoio. **Version:** 0.0.0.0 The **TBMANLIB_ConsoleComponents** contributed package is a set of text-interface components for console programs. It has progress bars ([**cProgressBar**](cProgressBar)), small line charts ([**cSparkline**](cSparkline)), bar charts ([**cVBar**](cVBar)), a table ([**cDataGrid**](cDataGrid)), bordered panels ([**cConsolePanel**](cConsolePanel)), a manager that places panels in a grid, a sidebar or a header and footer ([**cConsoleLayout**](cConsoleLayout)), colour themes ([**cConsoleTheme**](cConsoleTheme)), and helpers for colours and positions ([**cColorHelper**, **cLayoutHelper**](Helpers)). The components draw into the screen buffer of the full-screen mode of [**cConsole**](../TBMANLIB_ConsoleCore/cConsole), in the package [TBMANLIB_ConsoleCore](../TBMANLIB_ConsoleCore/); the program then writes the buffer to the console with [**Refresh**](../TBMANLIB_ConsoleCore/cConsole#refresh). This section documents version 0.0.0.0, published on TWINSERV on 1 February 2026 with no licence declared. The package describes itself as "TBMAN: Text UI (TUI) component library base on ConsoleCore". diff --git a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md index 5af82300..6fa3fc91 100644 --- a/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md +++ b/docs/Reference/Contributed/TBMANLIB_ConsoleCore/index.md @@ -11,7 +11,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_ConsoleCore/ # TBMANLIB_ConsoleCore Package {: .no_toc } -**Author:** woeoio. +**Author:** woeoio. **Version:** 1.0.0.1 The **TBMANLIB_ConsoleCore** contributed package is a library for the console of a twinBASIC program. Its class [**cConsole**](cConsole) writes text in 16 colours, reads lines, single keys and passwords, moves the cursor, switches the console to UTF-8 and to the escape-sequence mode, and has a full-screen mode in which a program draws into an in-memory grid, [**cConsoleBuffer**](cConsoleBuffer), and receives key, mouse and window-size events. The module [**mConsoleStyle**](mConsoleStyle) builds the escape sequences for colours, text styles and cursor movement, and has helpers that align, shorten and wrap text. This section documents version 1.0.0.1, published on TWINSERV on 3 February 2026 under the MIT licence. The package describes itself as "TBMAN: Modern console library with UTF-8, colors, and full-screen support". diff --git a/docs/Reference/Contributed/TBMANLIB_Diagnostic/index.md b/docs/Reference/Contributed/TBMANLIB_Diagnostic/index.md index b53b8051..f8a3dc4d 100644 --- a/docs/Reference/Contributed/TBMANLIB_Diagnostic/index.md +++ b/docs/Reference/Contributed/TBMANLIB_Diagnostic/index.md @@ -14,7 +14,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_Diagnostic/ # TBMANLIB_Diagnostic Package {: .no_toc } -**Author:** woeoio. +**Author:** woeoio. **Version:** 0.0.0.0 The **TBMANLIB_Diagnostic** contributed package makes a diagnostic report of a Windows computer and of the processes that run on it, and writes the report as text, JSON or HTML. The package has three parts. A [**DiagnosticEngine**](DiagnosticEngine) runs *collectors*, classes that each find one kind of information (the operating system, the processor and its load, the memory, the disks, the network, the running processes, the regional settings, the environment variables, the installed runtimes and the uptime), and each returns a [**DiagnosticResult**](DiagnosticResult), a list of pairs of text. A *formatter* turns the results into one string. [**FileHelper**](FileHelper) can save the string as a UTF-8 file. The package is written in twinBASIC and calls the Windows API directly. It uses no other library, and none of its collectors asks for administrator rights. diff --git a/docs/Reference/Contributed/TBMANLIB_Dialog/index.md b/docs/Reference/Contributed/TBMANLIB_Dialog/index.md index 4a1d11e0..3c4aa21e 100644 --- a/docs/Reference/Contributed/TBMANLIB_Dialog/index.md +++ b/docs/Reference/Contributed/TBMANLIB_Dialog/index.md @@ -8,7 +8,7 @@ indexed_from: 1.0.0.1 # TBMANLIB_Dialog Package -**Author:** woeoio +**Author:** woeoio. **Version:** 1.0.0.1 A twinBASIC package with one class, **cDialog**, that shows the Windows Open, Save As and Browse For Folder dialogs, builds the file-type filters of the first two, splits a file path into folder, name and extension, and opens a file in the program that Windows associates with it. The property names follow VB6's **CommonDialog** control. The **CommonDialog** class of the [VBComDlg](../VBComDlg/CommonDialog) package is the fuller alternative, with flags, a filter index, cancel errors and the Color, Font and Print dialogs. diff --git a/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md b/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md index 2620f0fa..95879ea7 100644 --- a/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md +++ b/docs/Reference/Contributed/TBMANLIB_ListBoxHScroll/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_ListBoxHScroll/ # TBMANLIB_ListBoxHScroll Package {: .no_toc } -**Author:** woeoio +**Author:** woeoio. **Version:** 1.0.0.1 The **TBMANLIB_ListBoxHScroll** contributed package provides a helper class that adds a functional horizontal scrollbar to a standard VB **ListBox** control by combining the `LB_SETHORIZONTALEXTENT` message, Win32 scroll-info APIs, and window subclassing. diff --git a/docs/Reference/Contributed/TBMANLIB_RES/index.md b/docs/Reference/Contributed/TBMANLIB_RES/index.md index 3d89d206..e0e9b2c7 100644 --- a/docs/Reference/Contributed/TBMANLIB_RES/index.md +++ b/docs/Reference/Contributed/TBMANLIB_RES/index.md @@ -8,7 +8,7 @@ indexed_from: 1.0.0.0 # TBMANLIB_RES Package -**Author:** woeoio +**Author:** woeoio. **Version:** 1.0.0.0 A twinBASIC package for loading binary resources embedded in a compiled executable and converting them to bytes, strings, hex, Base64, or pictures. diff --git a/docs/Reference/Contributed/TBMANLIB_Xml/index.md b/docs/Reference/Contributed/TBMANLIB_Xml/index.md index 20ef674e..b45cc0f9 100644 --- a/docs/Reference/Contributed/TBMANLIB_Xml/index.md +++ b/docs/Reference/Contributed/TBMANLIB_Xml/index.md @@ -11,7 +11,7 @@ permalink: /tB/Packages/Contributed/TBMANLIB_Xml/ # TBMANLIB_Xml Package {: .no_toc } -**Author:** woeoio. +**Author:** woeoio. **Version:** 1.0.0.0 The **TBMANLIB_Xml** contributed package reads, changes and writes XML documents. It has the shape of a small DOM. A [**cXml**](cXml) object holds a document as a tree of [**cXmlNode**](cXmlNode) objects, finds elements by a path such as `library/book`, and reads and writes the document as a string or as a UTF-8 file. The [**mXml**](mXml) module holds the node types, the error numbers and two functions that convert between strings and UTF-8 bytes. The package is written in twinBASIC and calls two functions of the Windows API for the conversion. This section documents version 1.0.0.0, published under the MIT licence. diff --git a/docs/Reference/Contributed/TwinTimerLib/index.md b/docs/Reference/Contributed/TwinTimerLib/index.md index d4f082ef..49ba4ae9 100644 --- a/docs/Reference/Contributed/TwinTimerLib/index.md +++ b/docs/Reference/Contributed/TwinTimerLib/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/TwinTimerLib/ # TwinTimerLib Package {: .no_toc } -**Author:** Krool +**Author:** Krool. **Version:** 1.0.7.0 The **TwinTimerLib** contributed package provides a Win32-backed timer class that fires a **Timer** event at a repeating interval and reports the total elapsed time in milliseconds. Unlike the built-in VB **Timer** control, **TwinTimer** does not require a form or control container and can be instantiated from any module. diff --git a/docs/Reference/Contributed/VBA_JSON/index.md b/docs/Reference/Contributed/VBA_JSON/index.md index b9ea94cb..1cde5d14 100644 --- a/docs/Reference/Contributed/VBA_JSON/index.md +++ b/docs/Reference/Contributed/VBA_JSON/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/VBA_JSON/ # VBA_JSON Package {: .no_toc } -**Author:** Tim Hall, published on TWINSERV by WaynePhillipsEA. **On GitHub:** [VBA-tools/VBA-JSON](https://github.com/VBA-tools/VBA-JSON) and [VBA-tools/VBA-UTC](https://github.com/VBA-tools/VBA-UTC), the VBA libraries the package is made from. +**Author:** Tim Hall, published on TWINSERV by WaynePhillipsEA. **Version:** 2.3.1.1. **On GitHub:** [VBA-tools/VBA-JSON](https://github.com/VBA-tools/VBA-JSON) and [VBA-tools/VBA-UTC](https://github.com/VBA-tools/VBA-UTC), the VBA libraries the package is made from. The **VBA_JSON** contributed package provides JSON parsing and serialization for VBA and twinBASIC projects, along with UTC and ISO 8601 date-conversion utilities. The package exposes a **JsonConverter** standard module containing the primary **ParseJson** and **ConvertToJson** functions, and a **Dictionary** class used to represent JSON objects in memory. diff --git a/docs/Reference/Contributed/VBComDlg/index.md b/docs/Reference/Contributed/VBComDlg/index.md index f394df99..cfb2b724 100644 --- a/docs/Reference/Contributed/VBComDlg/index.md +++ b/docs/Reference/Contributed/VBComDlg/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/VBComDlg/ # VBComDlg Package {: .no_toc } -**Author:** Krool +**Author:** Krool. **Version:** 1.0.3.0 The **VBComDlg** contributed package provides the **CommonDialog** class, which wraps the Windows common dialogs (File Open, File Save, Color, Font, Print, Page Setup, Folder Browser, Find, and Replace) and the WinHelp call. Its members are modelled on those of the VB6 CommonDialog control. diff --git a/docs/Reference/Contributed/WinReg/index.md b/docs/Reference/Contributed/WinReg/index.md index e3fc74d6..bb78c734 100644 --- a/docs/Reference/Contributed/WinReg/index.md +++ b/docs/Reference/Contributed/WinReg/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/WinReg/ # WinReg Package {: .no_toc } -**Author:** forliny. **On GitHub:** [forliny/TbWinReg](https://github.com/forliny/TbWinReg) +**Author:** forliny. **Version:** 0.0.0.0. **On GitHub:** [forliny/TbWinReg](https://github.com/forliny/TbWinReg) The **WinReg** contributed package provides a Windows Registry helper class that reads, writes, deletes, and enumerates registry keys and values through the Win32 `advapi32` API. The package exposes a single **RegCls** class wrapping the most common registry operations into a convenient interface. It depends on types and API declarations from the **WinDevLib** package. diff --git a/docs/Reference/Contributed/tbFileSysTools/index.md b/docs/Reference/Contributed/tbFileSysTools/index.md index 5f4dadf3..f70f14a4 100644 --- a/docs/Reference/Contributed/tbFileSysTools/index.md +++ b/docs/Reference/Contributed/tbFileSysTools/index.md @@ -13,7 +13,7 @@ permalink: /tB/Packages/Contributed/tbFileSysTools/ # tbFileSysTools Package {: .no_toc } -**Author:** GCuser99. **On GitHub:** [GCuser99/tbFileSysTools](https://github.com/GCuser99/tbFileSysTools), in the folder *Package*. +**Author:** GCuser99. **Version:** 1.1.1.0. **On GitHub:** [GCuser99/tbFileSysTools](https://github.com/GCuser99/tbFileSysTools), in the folder *Package*. The **tbFileSysTools** contributed package, listed in the Available Packages dialog as *File System Tools - Modern Replacement for FSO*, reads and changes files, folders and drives, as the **FileSystemObject** of the Scripting Runtime does, and is written in twinBASIC. It reads and writes text files in any Windows code page, with detection of the encoding and handling of byte-order marks (BOMs), detects and converts line endings, streams files of any size, and works with paths longer than 260 characters. diff --git a/docs/Reference/Contributed/tbProjPacker/index.md b/docs/Reference/Contributed/tbProjPacker/index.md index f8fac08b..ef78f7dc 100644 --- a/docs/Reference/Contributed/tbProjPacker/index.md +++ b/docs/Reference/Contributed/tbProjPacker/index.md @@ -12,7 +12,7 @@ permalink: /tB/Packages/Contributed/tbProjPacker/ # tbProjPacker Package {: .no_toc } -**Author:** GCuser99. **On GitHub:** [GCuser99/tbProjPacker](https://github.com/GCuser99/tbProjPacker), in the folder *Project*. +**Author:** GCuser99. **Version:** 1.0.5.0. **On GitHub:** [GCuser99/tbProjPacker](https://github.com/GCuser99/tbProjPacker), in the folder *Project*. The **tbProjPacker** contributed package unpacks a twinBASIC project file, a `.twinproj` or `.twinpack` file, into a folder of source files, and packs such a folder into a project file again. It does from twinBASIC code what the [Import/export tool](../../../../Features/Packages/Import-Export-Tool) does from a command line: [**Unpack**](ProjPacker/Unpack) corresponds to the tool's `export` command, and [**Pack**](ProjPacker/Pack) to its `import` command. diff --git a/docs/Reference/Contributed/tbRegExp/index.md b/docs/Reference/Contributed/tbRegExp/index.md index 18fd58ab..7c53c8dd 100644 --- a/docs/Reference/Contributed/tbRegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/index.md @@ -11,7 +11,7 @@ permalink: /tB/Packages/Contributed/tbRegExp/ # tbRegExp Package {: .no_toc } -**Author:** GCuser99. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. +**Author:** GCuser99. **Version:** 1.0.5.0. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. The **tbRegExp** contributed package provides regular expressions for twinBASIC projects, as a replacement for the **RegExp** object of VBScript. It follows the same object model. A [**RegExp**](RegExp/) is given a pattern and options, its [**Execute**](RegExp/Execute) method returns a [**MatchCollection**](MatchCollection/) of [**Match**](Match/) objects, and each **Match** holds the text captured by the groups of the pattern as a [**SubMatches**](SubMatches/) object. Positions are zero-based, as in VBScript. diff --git a/docs/Reference/Contributed/tsJson/index.md b/docs/Reference/Contributed/tsJson/index.md index 08b83462..02e51bcd 100644 --- a/docs/Reference/Contributed/tsJson/index.md +++ b/docs/Reference/Contributed/tsJson/index.md @@ -44,7 +44,7 @@ permalink: /tB/Packages/Contributed/tsJson/ # tsJson Package {: .no_toc } -**Author:** thosti. +**Author:** thosti. **Version:** 1.0.15.0 The **tsJson** contributed package reads, builds and writes JSON, finds values in a document with JSON Pointer and JSONPath, changes documents with JSON Patch and JSON Merge Patch, validates them against a JSON Schema, and converts ISO 8601 dates. The package describes itself as "Parse, query, patch, validate - one JSON model." This section documents version 1.0.15.0, published under the MIT licence. diff --git a/docs/Reference/Contributed/tsPwGen/index.md b/docs/Reference/Contributed/tsPwGen/index.md index 746d3357..cb42fc62 100644 --- a/docs/Reference/Contributed/tsPwGen/index.md +++ b/docs/Reference/Contributed/tsPwGen/index.md @@ -21,7 +21,7 @@ permalink: /tB/Packages/Contributed/tsPwGen/ # tsPwGen Package {: .no_toc } -**Author:** thosti. +**Author:** thosti. **Version:** 1.0.8.0 The **tsPwGen** contributed package generates passwords, PINs, hexadecimal tokens and passphrases, and computes the entropy of a recipe before anything is generated. The package describes itself as "Passwords you can measure before you generate." This section documents version 1.0.8.0, published under the MIT licence. diff --git a/docs/Reference/Contributed/xCalendar/index.md b/docs/Reference/Contributed/xCalendar/index.md index 50dc5947..20eaf662 100644 --- a/docs/Reference/Contributed/xCalendar/index.md +++ b/docs/Reference/Contributed/xCalendar/index.md @@ -9,7 +9,7 @@ permalink: /tB/Packages/Contributed/xCalendar/ # xCalendar Package {: .no_toc } -**Author:** sokinkeso. +**Author:** sokinkeso. **Version:** 1.0.7.0 The **xCalendar** contributed package provides a calendar control: a grid of the days of one month, in which the user selects a date by clicking a day, by pressing a key, or by choosing a month or a year from a list. It is meant as a replacement for the Calendar control of `MSCAL.OCX`. diff --git a/indexer/draft/workflow.mjs b/indexer/draft/workflow.mjs index e3763011..a6b90968 100644 --- a/indexer/draft/workflow.mjs +++ b/indexer/draft/workflow.mjs @@ -133,7 +133,7 @@ function listsPrompt(pkg) { (landing.permalink ? `, \`permalink: ${landing.permalink}\`` : ', a permalink of the form the landing pages beside it use') + `, \`has_toc: false\` and \`indexed_from: ${pkg.version}\`; ` + (landing.author - ? `under the H1, the line \`**Author:** ${landing.author}\`, or the author the package's sources name if they name someone else, followed by \`**On GitHub:** [owner/repo](url)\` when the sources name a repository that holds the package (WIP.md, the contributed packages); ` + ? `under the H1, the line \`**Author:** ${landing.author}. **Version:** ${pkg.version}\`, with the author the package's sources name in place of ${landing.author} if they name someone else, followed by \`. **On GitHub:** [owner/repo](url)\` when the sources name a repository that holds the package (WIP.md, the contributed packages); ` : '') + `a short description of the package from its sources (the \`source\` paths in the plan) and, when the sources name its GitHub repository, its README (\`gh api repos///readme --jq .content\` gives it in base64; use gh only to read): what the package adds over the object it replaces and what it does not support, where the README says so; then the lists, with no \`* TOC\` list when the page has only one or two sections. Model it on a landing page of another section in the same folder. List as a doubt each README claim the page states that no sample on it shows.\n\n` : '' From dc3696d8205305eb7edd7cccfde8318fa06a1d9e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:41:51 +0200 Subject: [PATCH 09/17] AutoCompleteLib: moved to 1.0.3.0, with its new AutoCompleteOptionRightToLeft --- docs/Reference/Contributed/AutoCompleteLib/AutoComplete.md | 1 + docs/Reference/Contributed/AutoCompleteLib/index.md | 4 ++-- .../Contributed/TBMANLIB_RES/{TBMAN.md => GLOBAL_RES.md} | 0 indexer/snapshots/contributed/AutoCompleteLib/api.json | 7 +++++-- test/example-projects/contributed-AutoCompleteLib/Settings | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) rename docs/Reference/Contributed/TBMANLIB_RES/{TBMAN.md => GLOBAL_RES.md} (100%) diff --git a/docs/Reference/Contributed/AutoCompleteLib/AutoComplete.md b/docs/Reference/Contributed/AutoCompleteLib/AutoComplete.md index b5738cd1..112a3708 100644 --- a/docs/Reference/Contributed/AutoCompleteLib/AutoComplete.md +++ b/docs/Reference/Contributed/AutoCompleteLib/AutoComplete.md @@ -79,6 +79,7 @@ Syntax: *object*.**Options** [ = *value* ] | **AutoCompleteOptionFilterPrefixes** | &H8 | Does not match common prefixes such as `www.` and `http://`. | | **AutoCompleteOptionUseTab** | &H10 | Selects the highlighted suggestion when the user presses **Tab**. | | **AutoCompleteOptionUpDownKeyDropsList** | &H20 | Opens the drop-down list when the user presses the **Up** or **Down** arrow key. | +| **AutoCompleteOptionRightToLeft** | &H40 | Shows the text of the drop-down list from right to left. | ## Methods diff --git a/docs/Reference/Contributed/AutoCompleteLib/index.md b/docs/Reference/Contributed/AutoCompleteLib/index.md index 12ef05d6..679a285f 100644 --- a/docs/Reference/Contributed/AutoCompleteLib/index.md +++ b/docs/Reference/Contributed/AutoCompleteLib/index.md @@ -2,14 +2,14 @@ title: AutoCompleteLib Package parent: Contributed Packages has_toc: false -indexed_from: 1.0.0.0 +indexed_from: 1.0.3.0 permalink: /tB/Packages/Contributed/AutoCompleteLib/ --- # AutoCompleteLib Package {: .no_toc } -**Author:** Krool. **Version:** 1.0.0.0 +**Author:** Krool. **Version:** 1.0.3.0 The **AutoCompleteLib** contributed package provides Windows shell auto-complete behavior for text-input controls. The package references the **AutoCompleteGuids** package, which holds the GUID and interface definitions the class uses. diff --git a/docs/Reference/Contributed/TBMANLIB_RES/TBMAN.md b/docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md similarity index 100% rename from docs/Reference/Contributed/TBMANLIB_RES/TBMAN.md rename to docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md diff --git a/indexer/snapshots/contributed/AutoCompleteLib/api.json b/indexer/snapshots/contributed/AutoCompleteLib/api.json index c6312be0..88564eca 100644 --- a/indexer/snapshots/contributed/AutoCompleteLib/api.json +++ b/indexer/snapshots/contributed/AutoCompleteLib/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "AutoCompleteLib", "project": "AutoCompleteLib", - "version": "1.0.0.0", + "version": "1.0.3.0", "types": [ { "name": "AutoComplete", @@ -24,6 +24,7 @@ {"name":"ACO_AUTOSUGGEST","kind":"const","vis":"private","signature":"Private Const ACO_AUTOSUGGEST As Long = &H1"}, {"name":"ACO_FILTERPREFIXES","kind":"const","vis":"private","signature":"Private Const ACO_FILTERPREFIXES As Long = &H8"}, {"name":"ACO_NONE","kind":"const","vis":"private","signature":"Private Const ACO_NONE As Long = &H0"}, + {"name":"ACO_RTLREADING","kind":"const","vis":"private","signature":"Private Const ACO_RTLREADING As Long = &H40"}, {"name":"ACO_SEARCH","kind":"const","vis":"private","signature":"Private Const ACO_SEARCH As Long = &H4"}, {"name":"ACO_UPDOWNKEYDROPSLIST","kind":"const","vis":"private","signature":"Private Const ACO_UPDOWNKEYDROPSLIST As Long = &H20"}, {"name":"ACO_USETAB","kind":"const","vis":"private","signature":"Private Const ACO_USETAB As Long = &H10"}, @@ -37,6 +38,7 @@ {"name":"AutoCompleteOptionAppend","kind":"field","vis":"private","signature":"Private AutoCompleteOptionAppend"}, {"name":"AutoCompleteOptionFilterPrefixes","kind":"field","vis":"private","signature":"Private AutoCompleteOptionFilterPrefixes"}, {"name":"AutoCompleteOptionNone","kind":"field","vis":"private","signature":"Private AutoCompleteOptionNone"}, + {"name":"AutoCompleteOptionRightToLeft","kind":"field","vis":"private","signature":"Private AutoCompleteOptionRightToLeft"}, {"name":"AutoCompleteOptionSearch","kind":"field","vis":"private","signature":"Private AutoCompleteOptionSearch"}, {"name":"AutoCompleteOptionSuggest","kind":"field","vis":"private","signature":"Private AutoCompleteOptionSuggest"}, {"name":"AutoCompleteOptionSuggestAppend","kind":"field","vis":"private","signature":"Private AutoCompleteOptionSuggestAppend"}, @@ -112,7 +114,8 @@ {"name":"AutoCompleteOptionSearch","value":"ACO_SEARCH"}, {"name":"AutoCompleteOptionFilterPrefixes","value":"ACO_FILTERPREFIXES"}, {"name":"AutoCompleteOptionUseTab","value":"ACO_USETAB"}, - {"name":"AutoCompleteOptionUpDownKeyDropsList","value":"ACO_UPDOWNKEYDROPSLIST"} + {"name":"AutoCompleteOptionUpDownKeyDropsList","value":"ACO_UPDOWNKEYDROPSLIST"}, + {"name":"AutoCompleteOptionRightToLeft","value":"ACO_RTLREADING"} ] }, { diff --git a/test/example-projects/contributed-AutoCompleteLib/Settings b/test/example-projects/contributed-AutoCompleteLib/Settings index d1f58ca0..ab284fa1 100644 --- a/test/example-projects/contributed-AutoCompleteLib/Settings +++ b/test/example-projects/contributed-AutoCompleteLib/Settings @@ -58,7 +58,7 @@ "versionBuild": "0", "versionMajor": "1", "versionMinor": "0", - "versionRevision": "0" + "versionRevision": "3" } ], "project.settingsVersion": 1, From 8ae12d0ab788c4a14dc8043aa779bc0d0c497ffd Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:41:52 +0200 Subject: [PATCH 10/17] TBMANLIB_RES: moved to 1.0.0.4, whose module TBMAN is now GLOBAL_RES; TBMANLIB's TBMAN page no longer names it --- docs/Reference/Contributed/TBMANLIB/TBMAN.md | 2 +- docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md | 10 +++++----- docs/Reference/Contributed/TBMANLIB_RES/index.md | 6 +++--- indexer/snapshots/contributed/TBMANLIB_RES/api.json | 10 +++++----- .../example-projects/contributed-TBMANLIB_RES/Settings | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/Reference/Contributed/TBMANLIB/TBMAN.md b/docs/Reference/Contributed/TBMANLIB/TBMAN.md index f8e60eb8..3b946404 100644 --- a/docs/Reference/Contributed/TBMANLIB/TBMAN.md +++ b/docs/Reference/Contributed/TBMANLIB/TBMAN.md @@ -22,7 +22,7 @@ Debug.Print TypeName(TBMAN.Json) The variables are declared `As New`, so each object is created the first time it is used. Because the instance is shared, its state is shared: the document in [**Json**](#json), the data in [**Csv**](#csv) and the settings in [**Logs**](#logs) are the same wherever the program reads them. A program that needs two documents, or logs with different settings, makes its own objects with `New`. -The package [TBMANLIB_RES](../TBMANLIB_RES/TBMAN) also has a module named **TBMAN**. The name of the package can be put in front of the name of the module, as `TBMANLIB.TBMAN.Json`, to say which module is meant. +The name of the package can be put in front of the name of the module, as `TBMANLIB.TBMAN.Json`, when another package the project references also has a module named **TBMAN**. ```tb check_build check_run Debug.Print TypeName(TBMANLIB.TBMAN.Json) diff --git a/docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md b/docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md index 3106597c..4a88af05 100644 --- a/docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md +++ b/docs/Reference/Contributed/TBMANLIB_RES/GLOBAL_RES.md @@ -1,11 +1,11 @@ --- -title: TBMAN +title: GLOBAL_RES parent: TBMANLIB_RES Package -permalink: /tB/Packages/Contributed/TBMANLIB_RES/TBMAN +permalink: /tB/Packages/Contributed/TBMANLIB_RES/GLOBAL_RES has_toc: false --- -# TBMAN module +# GLOBAL_RES module {: .no_toc } A standard module that exposes a pre-instantiated [**cRes**](cRes/) object as a public variable, providing package-wide access to resource loading without requiring a separate **cRes** instance. @@ -23,7 +23,7 @@ Public Res As New cRes Because of **As New**, the instance is created automatically the first time **Res** is referenced. It provides the same interface as a manually constructed **cRes** instance: [**Read**](cRes/Read), [**ReturnBytes**](cRes/ReturnBytes), [**ReturnString**](cRes/ReturnString), [**ReturnHex**](cRes/ReturnHex), [**ReturnBase64**](cRes/ReturnBase64), and [**ReturnPicture**](cRes/ReturnPicture). > [!NOTE] -> **TBMAN.Res** is a single shared instance for the entire project. Calling **Res.Read** replaces its internal byte buffer. If multiple callers read different resources in the same execution path, use separate **cRes** instances rather than sharing **TBMAN.Res**. +> **GLOBAL_RES.Res** is a single shared instance for the entire project. Calling **Res.Read** replaces its internal byte buffer. If multiple callers read different resources in the same execution path, use separate **cRes** instances rather than sharing **GLOBAL_RES.Res**. ## Example @@ -31,7 +31,7 @@ This example loads a PNG resource and assigns it to a **PictureBox** control. ```tb check_build Private Sub Form_Load() - Picture1.Picture = TBMAN.Res.Read(101, "PNG").ReturnPicture() + Picture1.Picture = GLOBAL_RES.Res.Read(101, "PNG").ReturnPicture() End Sub ``` diff --git a/docs/Reference/Contributed/TBMANLIB_RES/index.md b/docs/Reference/Contributed/TBMANLIB_RES/index.md index e0e9b2c7..3aa2b5f3 100644 --- a/docs/Reference/Contributed/TBMANLIB_RES/index.md +++ b/docs/Reference/Contributed/TBMANLIB_RES/index.md @@ -3,12 +3,12 @@ title: TBMANLIB_RES Package parent: Contributed Packages has_toc: false permalink: /tB/Packages/Contributed/TBMANLIB_RES/ -indexed_from: 1.0.0.0 +indexed_from: 1.0.0.4 --- # TBMANLIB_RES Package -**Author:** woeoio. **Version:** 1.0.0.0 +**Author:** woeoio. **Version:** 1.0.0.4 A twinBASIC package for loading binary resources embedded in a compiled executable and converting them to bytes, strings, hex, Base64, or pictures. @@ -18,7 +18,7 @@ A twinBASIC package for loading binary resources embedded in a compiled executab ## Modules -- [TBMAN](TBMAN) -- exposes a pre-instantiated `cRes` object as a public variable, providing package-wide access to resource loading without requiring a separate instance. +- [GLOBAL_RES](GLOBAL_RES) -- exposes a pre-instantiated `cRes` object as a public variable, providing package-wide access to resource loading without requiring a separate instance. ## Enumerations diff --git a/indexer/snapshots/contributed/TBMANLIB_RES/api.json b/indexer/snapshots/contributed/TBMANLIB_RES/api.json index 44c9d69d..ce892f6c 100644 --- a/indexer/snapshots/contributed/TBMANLIB_RES/api.json +++ b/indexer/snapshots/contributed/TBMANLIB_RES/api.json @@ -2,16 +2,16 @@ "format": 3, "package": "TBMANLIB_RES", "project": "TBMANLIB_RES", - "version": "1.0.0.0", + "version": "1.0.0.4", "types": [ { - "name": "TBMAN", + "name": "GLOBAL_RES", "kind": "module", "vis": "public", - "file": "TBMAN.twin", - "signature": "Module TBMAN", + "file": "GLOBAL_RES.twin", + "signature": "Module GLOBAL_RES", "members": [ - {"name":"Res","kind":"field","vis":"public","signature":"Public Res As new cRes"} + {"name":"Res","kind":"field","vis":"public","signature":"Public Res As New cRes"} ] }, { diff --git a/test/example-projects/contributed-TBMANLIB_RES/Settings b/test/example-projects/contributed-TBMANLIB_RES/Settings index 24c5eedb..f32dec65 100644 --- a/test/example-projects/contributed-TBMANLIB_RES/Settings +++ b/test/example-projects/contributed-TBMANLIB_RES/Settings @@ -51,11 +51,11 @@ "autoCtlExt": true, "id": "{86D452C1-BB0C-4CED-9427-C0615CF459CA}", "licence": "MIT", - "name": "[IMPORTED] [TBMAN] Easy to use ResourcesFiles with Res object", + "name": "[IMPORTED] TBMAN: Easy to use ResourcesFiles with Res object", "path32": "/Packages/TBMANLIB_RES", "path64": "/Packages/TBMANLIB_RES", "symbolId": "TBMANLIB_RES", - "versionBuild": "0", + "versionBuild": "4", "versionMajor": "1", "versionMinor": "0", "versionRevision": "0" From 3da3dc2f9da2364db9356c91420d218dcdf91a9e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 22:59:07 +0200 Subject: [PATCH 11/17] tbProjPacker: moved to 1.1.0.0, whose Pack converts code files under a Sources folder to CR LF and whose self-test has a 24th test; modPackUnpack is now modImpExp --- WIP.md | 2 +- .../tbProjPacker/ProjPacker/Pack.md | 24 +++++++- .../tbProjPacker/ProjPacker/Test.md | 14 ++--- .../Contributed/tbProjPacker/index.md | 10 +-- .../contributed/tbProjPacker/api.json | 61 +++++++++++-------- .../contributed-tbProjPacker/Settings | 4 +- 6 files changed, 72 insertions(+), 43 deletions(-) diff --git a/WIP.md b/WIP.md index 8e29b878..7b2a9eb8 100644 --- a/WIP.md +++ b/WIP.md @@ -34,7 +34,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modPackUnpack` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. diff --git a/docs/Reference/Contributed/tbProjPacker/ProjPacker/Pack.md b/docs/Reference/Contributed/tbProjPacker/ProjPacker/Pack.md index 284bb5db..1b8e4da3 100644 --- a/docs/Reference/Contributed/tbProjPacker/ProjPacker/Pack.md +++ b/docs/Reference/Contributed/tbProjPacker/ProjPacker/Pack.md @@ -33,7 +33,7 @@ Returns **True** when *outputFile* was written, and **False** when it was not. T The root of the project file is named after the last folder of *inputDir*. Everything in *inputDir* is stored, in all its subfolders: hidden files, empty folders and a `.git` folder included. Keep the project's files in a folder of their own. The top folder of a Git repository would put the repository's own data into the project file. -Version 1.0.5.0 stores each file exactly as it is on disk. It does not convert line endings. The IDE stores `.twin`, `.bas` and `.cls` files with CR LF line endings, so a checkout that has changed them to LF is packed with LF. +Every file is stored as it is on disk, except the code files that [Line endings](#line-endings) describes. Every project that the IDE exports has the folders `Resources`, `Sources`, `ImportedTypeLibraries`, `Miscellaneous` and `Packages`, even when they are empty. Git does not store an empty folder, so a folder checked out from a repository can lack some of them. **Pack** does not add the missing folders. It prints two lines after the summary line, and still returns **True**: @@ -42,6 +42,28 @@ Every project that the IDE exports has the folders `Resources`, `Sources`, `Impo twinBASIC should rebuild them on Open Project. ``` +## Line endings + +The IDE stores `.twin`, `.bas` and `.cls` files with CR LF line endings. A checkout that Git or an editor has changed to LF would otherwise be packed with LF, so **Pack** converts these files to CR LF while it packs them. A file is converted when both of these hold: + +- Its extension is `.twin`, `.bas` or `.cls`, in any letter case. +- It is in a folder named `Sources`, or in a folder below one. The folder name is matched in exact letter case and can be at any depth below *inputDir*: `Sources\Forms`, `Resources\Sources` and `Other\Sources` count, and `sources` does not. + +Every other file is stored as it is on disk, a text file in `Sources` and a code file outside it included. The folder *inputDir* itself is not tested for its name. + +The conversion removes every CR and then turns every LF into CR LF. A file that already has CR LF line endings comes out unchanged. The files on disk are never changed; only the copy in the project file is. + +> [!NOTE] +> A CR that is not followed by LF is removed, and no line break replaces it. A code file whose lines end in a CR alone, as old Macintosh text files do, is packed as one line. The Import/export tool leaves such a CR in place. + +After the summary line, **Pack** prints the number of files that the conversion changed. A file that already had CR LF line endings is not counted, and when no file changed, the line is not printed: + +``` + note: converted 7 code file(s) under Sources from Unix (LF) to Windows (CRLF) line endings. +``` + +The line follows the note about missing folders, when there is one. + ## Refusals **Pack** returns **False** and writes nothing in these cases: diff --git a/docs/Reference/Contributed/tbProjPacker/ProjPacker/Test.md b/docs/Reference/Contributed/tbProjPacker/ProjPacker/Test.md index 848320f1..67c4bb2b 100644 --- a/docs/Reference/Contributed/tbProjPacker/ProjPacker/Test.md +++ b/docs/Reference/Contributed/tbProjPacker/ProjPacker/Test.md @@ -25,7 +25,7 @@ Returns **True** when no test failed, and **False** when a test failed or *sampl ## What the tests check -There are 23 tests. Each runs on its own, so a failure in one does not stop the others. The tests work in a new folder, named `impexp-test-` and a number, in the folder that the `TEMP` environment variable names. The folder is deleted when the tests end. +There are 24 tests. Each runs on its own, so a failure in one does not stop the others. The tests work in a new folder, named `impexp-test-` and a number, in the folder that the `TEMP` environment variable names. The folder is deleted when the tests end. Four tests need the sample file: @@ -34,11 +34,11 @@ Four tests need the sample file: - Writing, parsing and writing again gives the same bytes both times. - Unpacking the sample, packing the folder and unpacking that file gives two folders with the same files and the same bytes. -Nineteen tests need no sample: +Twenty tests need no sample: - **File format (6).** An empty project, a project with one file, the flags of the entries, Unicode names with their sort order, a file with a wrong magic number, and a file cut short. - **Long path (1).** A file whose path is longer than 260 characters survives a pack and an unpack. -- **Pack (4).** [**Pack**](Pack) refuses a folder with no `Settings` file and accepts one with it. It refuses to replace an existing file, and replaces it when *overwrite* is **True**. +- **Pack (5).** [**Pack**](Pack) refuses a folder with no `Settings` file and accepts one with it. It refuses to replace an existing file, and replaces it when *overwrite* is **True**. It converts the [line endings](Pack#line-endings) of the code files under `Sources`, and leaves a text file there and a code file elsewhere as they are. - **Unpack with *cleanFirst* (6).** [**Unpack**](Unpack) removes leftover files, counts the levels of a path correctly, refuses a folder that has no `Settings` file and a folder whose `Settings` is a folder, and accepts a project folder and an empty folder. - **Other refusals (2).** **Pack** refuses a folder whose `Settings` is a folder. **Unpack** reports a project file that does not exist. @@ -55,21 +55,21 @@ Sample: C:\...\imagestrip.twinproj [INFO] root "imagestrip", 18 files, 6 directories, 170595 bytes [PASS] Parse sample (invariants + re-parse consistency) [PASS] In-memory round-trip (parse -> serialize -> re-parse) - ... 21 more lines, one for each of the other tests ... + ... 22 more lines, one for each of the other tests ... -23/23 tests passed. +24/24 tests passed. ``` Without a sample, the four sample tests print `[SKIP]` and the summary ends with the number skipped: ``` -19/19 tests passed (4 skipped -- pass a .twinproj or .twinpack path to run them). +20/20 tests passed (4 skipped -- pass a .twinproj or .twinpack path to run them). ``` A *samplePath* that does not exist prints `Sample not found: ` and the path. No test runs. > [!NOTE] -> An empty *samplePath* does not make the method fail. With 19 of the 19 tests that run passed and 4 skipped, it returns **True**. Pass a project file to run all 23. +> An empty *samplePath* does not make the method fail. With 20 of the 20 tests that run passed and 4 skipped, it returns **True**. Pass a project file to run all 24. ## Example diff --git a/docs/Reference/Contributed/tbProjPacker/index.md b/docs/Reference/Contributed/tbProjPacker/index.md index ef78f7dc..bf99520c 100644 --- a/docs/Reference/Contributed/tbProjPacker/index.md +++ b/docs/Reference/Contributed/tbProjPacker/index.md @@ -3,22 +3,22 @@ title: tbProjPacker Package parent: Contributed Packages has_toc: false exclude_from_docs: - - modPackUnpack + - modImpExp - modWin32 -indexed_from: 1.0.5.0 +indexed_from: 1.1.0.0 permalink: /tB/Packages/Contributed/tbProjPacker/ --- # tbProjPacker Package {: .no_toc } -**Author:** GCuser99. **Version:** 1.0.5.0. **On GitHub:** [GCuser99/tbProjPacker](https://github.com/GCuser99/tbProjPacker), in the folder *Project*. +**Author:** GCuser99. **Version:** 1.1.0.0. **On GitHub:** [GCuser99/tbProjPacker](https://github.com/GCuser99/tbProjPacker), in the folder *Project*. The **tbProjPacker** contributed package unpacks a twinBASIC project file, a `.twinproj` or `.twinpack` file, into a folder of source files, and packs such a folder into a project file again. It does from twinBASIC code what the [Import/export tool](../../../../Features/Packages/Import-Export-Tool) does from a command line: [**Unpack**](ProjPacker/Unpack) corresponds to the tool's `export` command, and [**Pack**](ProjPacker/Pack) to its `import` command. A project file is one binary file, which version control can neither compare nor merge. The folder it unpacks to is made of text files, which it can. A build routine can also unpack a copy of a project, change the copy (remove helper code, edit the `Settings` file) and pack it for release, and the original project is not touched. -The package has one public class, [**ProjPacker**](ProjPacker/), with three methods: **Unpack** and **Pack**, and [**Test**](ProjPacker/Test), which runs the package's own tests. A project that references the package sees nothing else. The code that reads and writes the file format, the Windows calls under it and the tests are in private modules and classes. This section documents version 1.0.5.0, published under the MIT licence. +The package has one public class, [**ProjPacker**](ProjPacker/), with three methods: **Unpack** and **Pack**, and [**Test**](ProjPacker/Test), which runs the package's own tests. A project that references the package sees nothing else. The code that reads and writes the file format, the Windows calls under it and the tests are in private modules and classes. This section documents version 1.1.0.0, published under the MIT licence. ```tb check_build Dim pp As New ProjPacker @@ -53,7 +53,7 @@ Some calls are refused, and return **False**, because they would lose data or pr The tool's script and the package read and write the same file format. They differ in what they do around it: -- The tool's `import` converts LF line endings to CRLF in `.twin`, `.bas` and `.cls` files. **Pack** stores every file as it is. +- The tool's `import` converts LF line endings to CRLF in every `.twin`, `.bas` and `.cls` file. **Pack** converts them only in a folder named `Sources` and the folders below it, and stores every other file as it is. The tool leaves a CR that is not followed by LF in place, and **Pack** removes it. [**Pack**](ProjPacker/Pack#line-endings) describes the rule. - The script skips a `.git` folder. **Pack** packs it, with every other hidden file and empty folder. - The script adds the folders that the IDE always writes (`ImportedTypeLibraries`, `Miscellaneous`, `Packages`, `Resources` and `Sources`) when the folder lacks them. **Pack** adds none and prints a note naming the missing ones. - The tool's `export` refuses to replace files already in the folder unless `--overwrite` is given. **Unpack** replaces them without asking, and has *cleanFirst* to empty the folder first. diff --git a/indexer/snapshots/contributed/tbProjPacker/api.json b/indexer/snapshots/contributed/tbProjPacker/api.json index 12c18cd0..0b72c8cc 100644 --- a/indexer/snapshots/contributed/tbProjPacker/api.json +++ b/indexer/snapshots/contributed/tbProjPacker/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "tbProjPacker", "project": "tbProjPacker", - "version": "1.0.5.0", + "version": "1.1.0.0", "types": [ { "name": "ByteBuffer", @@ -109,29 +109,25 @@ ] }, { - "name": "modOutput", + "name": "modExample", "kind": "module", "vis": "private", "public": false, - "file": "modOutput.twin", - "signature": "Private Module modOutput", + "file": "Examples/modExample.twin", + "signature": "Private Module modExample", "members": [ - {"name":"LogClose","kind":"sub","vis":"public","signature":"Public Sub LogClose()"}, - {"name":"LogOpen","kind":"sub","vis":"public","signature":"Public Sub LogOpen(ByVal path As String)"}, - {"name":"Say","kind":"sub","vis":"public","signature":"Public Sub Say(ByVal s As String)"}, - {"name":"mLogHandle","kind":"field","vis":"private","signature":"Private mLogHandle As LongPtr"}, - {"name":"mLogOpen","kind":"field","vis":"private","signature":"Private mLogOpen As Boolean"} + {"name":"Example","kind":"sub","vis":"private","signature":"Private Sub Example()"} ] }, { - "name": "modPackUnpack", + "name": "modImpExp", "kind": "module", "vis": "private", "public": false, "file": "modImpExp.twin", - "signature": "Private Module modPackUnpack", + "signature": "Private Module modImpExp", "members": [ - {"name":"BuildTree","kind":"function","vis":"private","signature":"Private Function BuildTree(ByVal dirPath As String) As Entry","returnType":"Entry"}, + {"name":"BuildTree","kind":"function","vis":"private","signature":"Private Function BuildTree(ByVal dirPath As String, Optional ByVal withinSources As Boolean = False) As Entry","returnType":"Entry"}, {"name":"CategoryFor","kind":"function","vis":"public","signature":"Public Function CategoryFor(ByVal name As String) As Byte","returnType":"Byte"}, {"name":"CleanTargetForImport","kind":"sub","vis":"private","signature":"Private Sub CleanTargetForImport(ByVal outputDir As String)"}, {"name":"CountEntry","kind":"sub","vis":"private","signature":"Private Sub CountEntry(ByVal e As Entry, ByRef res As PP_RESULT)"}, @@ -168,13 +164,14 @@ {"name":"SerializeTree","kind":"function","vis":"public","signature":"Public Function SerializeTree(ByVal root As Entry, ByRef outLen As Long) As Byte()","returnType":"Byte()"}, {"name":"WellKnownCategoryNames","kind":"function","vis":"private","signature":"Private Function WellKnownCategoryNames() As String","returnType":"String"}, {"name":"WriteEntry","kind":"sub","vis":"private","signature":"Private Sub WriteEntry(ByVal bb As ByteBuffer, ByVal e As Entry, ByRef isFirst As Boolean)"}, - {"name":"WriteStr","kind":"sub","vis":"private","signature":"Private Sub WriteStr(ByVal bb As ByteBuffer, ByVal s As String)"} + {"name":"WriteStr","kind":"sub","vis":"private","signature":"Private Sub WriteStr(ByVal bb As ByteBuffer, ByVal s As String)"}, + {"name":"mNormalizedCount","kind":"field","vis":"private","signature":"Private mNormalizedCount As Long"} ] }, { "name": "EntryKindEnum", "kind": "enum", - "in": "modPackUnpack", + "in": "modImpExp", "vis": "public", "file": "modImpExp.twin", "signature": "Public Enum EntryKindEnum", @@ -186,7 +183,7 @@ { "name": "PP_RESULT", "kind": "type", - "in": "modPackUnpack", + "in": "modImpExp", "vis": "public", "public": false, "file": "modImpExp.twin", @@ -199,6 +196,21 @@ ], "members": [] }, + { + "name": "modOutput", + "kind": "module", + "vis": "private", + "public": false, + "file": "modOutput.twin", + "signature": "Private Module modOutput", + "members": [ + {"name":"LogClose","kind":"sub","vis":"public","signature":"Public Sub LogClose()"}, + {"name":"LogOpen","kind":"sub","vis":"public","signature":"Public Sub LogOpen(ByVal path As String)"}, + {"name":"Say","kind":"sub","vis":"public","signature":"Public Sub Say(ByVal s As String)"}, + {"name":"mLogHandle","kind":"field","vis":"private","signature":"Private mLogHandle As LongPtr"}, + {"name":"mLogOpen","kind":"field","vis":"private","signature":"Private mLogOpen As Boolean"} + ] + }, { "name": "modSelfTest", "kind": "module", @@ -214,7 +226,9 @@ {"name":"CountRoot","kind":"sub","vis":"private","signature":"Private Sub CountRoot(ByVal root As Entry, ByRef fileCount As Long, ByRef dirCount As Long)"}, {"name":"CountTree","kind":"sub","vis":"private","signature":"Private Sub CountTree(ByVal e As Entry, ByRef fileCount As Long, ByRef dirCount As Long)"}, {"name":"EntryContentEqual","kind":"function","vis":"private","signature":"Private Function EntryContentEqual(ByVal x As Entry, ByVal y As Entry) As Boolean","returnType":"Boolean"}, + {"name":"EntryIsCRLF","kind":"function","vis":"private","signature":"Private Function EntryIsCRLF(ByVal root As Entry, ByVal relPath As String) As Boolean","returnType":"Boolean"}, {"name":"Fail","kind":"sub","vis":"private","signature":"Private Sub Fail(ByVal msg As String)"}, + {"name":"FindEntry","kind":"function","vis":"private","signature":"Private Function FindEntry(ByVal root As Entry, ByVal relPath As String) As Entry","returnType":"Entry"}, {"name":"FlattenTree","kind":"sub","vis":"private","signature":"Private Sub FlattenTree(ByVal e As Entry, ByVal prefix As String, ByVal paths As Collection, ByVal entries As Collection)"}, {"name":"Info","kind":"sub","vis":"private","signature":"Private Sub Info(ByVal msg As String)"}, {"name":"MakeProjectTree","kind":"function","vis":"private","signature":"Private Function MakeProjectTree(ByVal name As String, ByVal withSettings As Boolean) As String","returnType":"String"}, @@ -234,6 +248,7 @@ {"name":"T_Idempotence","kind":"sub","vis":"private","signature":"Private Sub T_Idempotence()"}, {"name":"T_ImportMissingInput","kind":"sub","vis":"private","signature":"Private Sub T_ImportMissingInput()"}, {"name":"T_InMemoryRoundTrip","kind":"sub","vis":"private","signature":"Private Sub T_InMemoryRoundTrip()"}, + {"name":"T_LineEndingNormalization","kind":"sub","vis":"private","signature":"Private Sub T_LineEndingNormalization()"}, {"name":"T_LongPath","kind":"sub","vis":"private","signature":"Private Sub T_LongPath()"}, {"name":"T_OverwriteGuardFires","kind":"sub","vis":"private","signature":"Private Sub T_OverwriteGuardFires()"}, {"name":"T_OverwritePassesWithFlag","kind":"sub","vis":"private","signature":"Private Sub T_OverwritePassesWithFlag()"}, @@ -245,6 +260,7 @@ {"name":"T_TruncationRejected","kind":"sub","vis":"private","signature":"Private Sub T_TruncationRejected()"}, {"name":"T_UnicodeAndOrdering","kind":"sub","vis":"private","signature":"Private Sub T_UnicodeAndOrdering()"}, {"name":"WalkDisk","kind":"sub","vis":"private","signature":"Private Sub WalkDisk(ByVal dirPath As String, ByVal prefix As String, ByVal paths As Collection)"}, + {"name":"WriteLfFile","kind":"sub","vis":"private","signature":"Private Sub WriteLfFile(ByVal path As String, ByVal s As String)"}, {"name":"mFailed","kind":"field","vis":"private","signature":"Private mFailed As Long"}, {"name":"mHasSample","kind":"field","vis":"private","signature":"Private mHasSample As Boolean"}, {"name":"mPassed","kind":"field","vis":"private","signature":"Private mPassed As Long"}, @@ -266,13 +282,16 @@ {"name":"AbsPath","kind":"function","vis":"public","signature":"Public Function AbsPath(ByVal p As String) As String","returnType":"String"}, {"name":"ApiPath","kind":"function","vis":"public","signature":"Public Function ApiPath(ByVal canonicalAbsPath As String) As String","returnType":"String"}, {"name":"BaseName","kind":"function","vis":"public","signature":"Public Function BaseName(ByVal p As String) As String","returnType":"String"}, + {"name":"CodeExtensions","kind":"function","vis":"public","signature":"Public Function CodeExtensions() As String","returnType":"String"}, {"name":"DeleteTree","kind":"sub","vis":"public","signature":"Public Sub DeleteTree(ByVal dirPath As String)"}, {"name":"EnsureDirectory","kind":"sub","vis":"public","signature":"Public Sub EnsureDirectory(ByVal p As String)"}, + {"name":"IsCodeFileName","kind":"function","vis":"public","signature":"Public Function IsCodeFileName(ByVal fileName As String) As Boolean","returnType":"Boolean"}, {"name":"IsDirEmpty","kind":"function","vis":"public","signature":"Public Function IsDirEmpty(ByVal dirPath As String) As Boolean","returnType":"Boolean"}, {"name":"IsDirectory","kind":"function","vis":"public","signature":"Public Function IsDirectory(ByVal p As String) As Boolean","returnType":"Boolean"}, {"name":"IsFile","kind":"function","vis":"public","signature":"Public Function IsFile(ByVal p As String) As Boolean","returnType":"Boolean"}, {"name":"JoinPath","kind":"function","vis":"public","signature":"Public Function JoinPath(ByVal a As String, ByVal b As String) As String","returnType":"String"}, {"name":"ListDirectory","kind":"sub","vis":"public","signature":"Public Sub ListDirectory(ByVal dirPath As String, ByRef outNames() As String, ByRef outIsDir() As Boolean, ByRef outCount As Long)"}, + {"name":"NormalizeNewlines","kind":"function","vis":"public","signature":"Public Function NormalizeNewlines(ByRef inBuf() As Byte, ByVal inLen As Long, ByRef outBuf() As Byte, ByRef outLen As Long) As Boolean","returnType":"Boolean"}, {"name":"OrdinalCompare","kind":"function","vis":"public","signature":"Public Function OrdinalCompare(ByVal a As String, ByVal b As String) As Long","returnType":"Long"}, {"name":"PP_LONGPATH_THRESHOLD","kind":"const","vis":"private","signature":"Private Const PP_LONGPATH_THRESHOLD As Long = 248"}, {"name":"ParentPath","kind":"function","vis":"public","signature":"Public Function ParentPath(ByVal p As String) As String","returnType":"String"}, @@ -286,18 +305,6 @@ {"name":"WriteWholeFile","kind":"sub","vis":"public","signature":"Public Sub WriteWholeFile(ByVal path As String, ByRef buf() As Byte, ByVal length As Long)"} ] }, - { - "name": "modTest", - "kind": "module", - "vis": "private", - "public": false, - "file": "Examples/modTest.twin", - "signature": "Private Module modTest", - "members": [ - {"name":"PackTwinProj","kind":"sub","vis":"private","signature":"Private Sub PackTwinProj()"}, - {"name":"UnpackTwinProj","kind":"sub","vis":"private","signature":"Private Sub UnpackTwinProj()"} - ] - }, { "name": "modWin32", "kind": "module", diff --git a/test/example-projects/contributed-tbProjPacker/Settings b/test/example-projects/contributed-tbProjPacker/Settings index 36ae5b1c..c0ace8e3 100644 --- a/test/example-projects/contributed-tbProjPacker/Settings +++ b/test/example-projects/contributed-tbProjPacker/Settings @@ -57,8 +57,8 @@ "symbolId": "tbProjPacker", "versionBuild": "0", "versionMajor": "1", - "versionMinor": "0", - "versionRevision": "5" + "versionMinor": "1", + "versionRevision": "0" } ], "project.settingsVersion": 1, From 0894fab243153ef50ab4cdfb4f3a5ca0bb526356 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:08:38 +0200 Subject: [PATCH 12/17] VBComDlg: moved to 1.0.13.0, whose dialogs are task-modal with no active window and whose CustomColors coerces each element; CommonDialogBase excluded --- WIP.md | 2 +- .../Contributed/VBComDlg/CommonDialog.md | 14 ++++++++++---- docs/Reference/Contributed/VBComDlg/index.md | 6 ++++-- indexer/snapshots/contributed/VBComDlg/api.json | 15 +++++++++++++-- .../contributed-VBComDlg/Settings | 4 ++-- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/WIP.md b/WIP.md index 7b2a9eb8..3388300f 100644 --- a/WIP.md +++ b/WIP.md @@ -34,7 +34,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. diff --git a/docs/Reference/Contributed/VBComDlg/CommonDialog.md b/docs/Reference/Contributed/VBComDlg/CommonDialog.md index 4cb5320b..666b452d 100644 --- a/docs/Reference/Contributed/VBComDlg/CommonDialog.md +++ b/docs/Reference/Contributed/VBComDlg/CommonDialog.md @@ -33,6 +33,12 @@ Assigning a value outside the documented range or set of constants to a property * TOC {:toc} +## Owner window + +The owner of a dialog is the active window of the calling thread. If that window has an MDI client window, the owner is the active MDI child, or the MDI client itself when it has no active child. + +When the thread has no active window --- in a program that has no form, for example --- the File Open, File Save, Color, Font, Print, Page Setup and Folder Browser dialogs have no owner and are task-modal, as a message box with the **MB_TASKMODAL** style is: while the dialog is shown, the class disables every enabled top-level window of the thread, and it enables those windows again when the dialog closes. A window that was already disabled stays disabled. The extended Print dialog needs an owner, so it then uses the desktop window, and is task-modal in the same way. The Find and Replace dialogs also need an owner, so they are given a hidden one (see [**ShowFind**](#showfind)). + ## Properties ### Action @@ -91,7 +97,7 @@ The 16 custom colors shown in the lower half of the Color dialog. Syntax: *object*.**CustomColors** [ = *value* ] *value* -: A single-dimensioned array of up to 16 numeric values (Long, Integer, Byte, Double, or Single). Each element is an RGB value or OLE color. The class reads the first 16 elements and ignores the rest. An element of any other type leaves the corresponding color unchanged. Assigning a multi-dimensional array raises run-time error 5; assigning an unallocated array raises run-time error 91. Assigning `Empty` has no effect; any other value that is not an array raises run-time error 380. +: A single-dimensioned array of up to 16 values. Each element is converted to a **Long** and then to RGB, so it is an RGB value or an OLE color, and a **String** that holds a number is accepted. The first element of the array is the first custom color, whatever the array's lower bound. The class reads the first 16 elements and ignores the rest; with fewer than 16 elements, the remaining colors are unchanged. An element that cannot be converted raises run-time error 13 (*Type mismatch*), or run-time error 94 (*Invalid use of Null*) for a **Null** element, and the elements before it have already been stored. Assigning a multi-dimensional array raises run-time error 5; assigning an unallocated array raises run-time error 91. Assigning `Empty` restores the 16 default colors; any other value that is not an array raises run-time error 380. The getter returns a **Variant** array of 16 **Long** values (index 0 to 15). @@ -521,7 +527,7 @@ Opens a modeless Find dialog and returns the dialog's window handle. Returns 0 i Syntax: *object*.**ShowFind** ( ) **As LongPtr** -The dialog is non-modal: it remains open while the user interacts with the application. When the user clicks **Find Next**, [**FindWhat**](#findwhat) and [**Flags**](#flags) are updated and the [**FindNext**](#findnext) event fires. When the dialog closes, the internal handle is released automatically. Call this method again to reopen the dialog. The method returns 0 while a Find or Replace dialog opened by the same **CommonDialog** object is still open. +The dialog is non-modal: it remains open while the user interacts with the application. When the user clicks **Find Next**, [**FindWhat**](#findwhat) and [**Flags**](#flags) are updated and the [**FindNext**](#findnext) event fires. When the dialog closes, the internal handle is released automatically. Call this method again to reopen the dialog. The method returns 0 while a Find or Replace dialog opened by the same **CommonDialog** object is still open. The dialog needs an owner window: when the thread has no active window, the owner is a hidden window that the class creates for the dialog and destroys when the dialog closes. If the dialog cannot be created, the method raises **CdlBufferLengthZero** (36848) when the *Find what* buffer is invalid. @@ -595,7 +601,7 @@ Displays the extended Print dialog (the `PrintDlgEx` function) and returns a **C Syntax: *object*.**ShowPrinterEx** ( ) **As CdlPDResultConstants** -Returns **CdlPDResultPrint** (1) when the user clicked **Print**, **CdlPDResultApply** (2) for **Apply**, or **CdlPDResultCancel** (0) for **Cancel**. Properties are updated on non-cancel results, the same as [**ShowPrinter**](#showprinter). When the user chooses **Cancel** and [**CancelError**](#cancelerror) is **True**, error `CdlCancel` is raised. The extended dialog requires a valid owner window; when the thread has no active window, the method uses the desktop window as the owner. When `PrintDlgEx` fails with an out-of-memory, invalid-argument, invalid-pointer, invalid-handle or unspecified error, the method raises **CdlInitFailure** (28665). +Returns **CdlPDResultPrint** (1) when the user clicked **Print**, **CdlPDResultApply** (2) for **Apply**, or **CdlPDResultCancel** (0) for **Cancel**. Properties are updated on non-cancel results, the same as [**ShowPrinter**](#showprinter). When the user chooses **Cancel** and [**CancelError**](#cancelerror) is **True**, error `CdlCancel` is raised. The extended dialog requires a valid owner window; when the thread has no active window, the method uses the desktop window as the owner, and the dialog is task-modal (see [Owner window](#owner-window)). When `PrintDlgEx` fails with an out-of-memory, invalid-argument, invalid-pointer, invalid-handle or unspecified error, the method raises **CdlInitFailure** (28665). ### ShowReplace {: .no_toc } @@ -751,7 +757,7 @@ Declared for the **Replace All** button of the Replace dialog. Syntax: *object*\_**ReplaceAll**( ) > [!NOTE] -> In version 1.0.3.0 of the package the class never raises this event. Its test for the **Replace All** button compares the masked flags with **CdlFRFindNext** instead of **CdlFRReplaceAll**, so the comparison is never true. Clicking **Replace All** raises none of the events. +> In version 1.0.13.0 of the package the class never raises this event. Its test for the **Replace All** button compares the masked flags with **CdlFRFindNext** instead of **CdlFRReplaceAll**, so the comparison is never true. Clicking **Replace All** raises none of the events. ## Example diff --git a/docs/Reference/Contributed/VBComDlg/index.md b/docs/Reference/Contributed/VBComDlg/index.md index cfb2b724..db559918 100644 --- a/docs/Reference/Contributed/VBComDlg/index.md +++ b/docs/Reference/Contributed/VBComDlg/index.md @@ -2,14 +2,16 @@ title: VBComDlg Package parent: Contributed Packages has_toc: false -indexed_from: 1.0.3.0 +exclude_from_docs: + - CommonDialogBase +indexed_from: 1.0.13.0 permalink: /tB/Packages/Contributed/VBComDlg/ --- # VBComDlg Package {: .no_toc } -**Author:** Krool. **Version:** 1.0.3.0 +**Author:** Krool. **Version:** 1.0.13.0 The **VBComDlg** contributed package provides the **CommonDialog** class, which wraps the Windows common dialogs (File Open, File Save, Color, Font, Print, Page Setup, Folder Browser, Find, and Replace) and the WinHelp call. Its members are modelled on those of the VB6 CommonDialog control. diff --git a/indexer/snapshots/contributed/VBComDlg/api.json b/indexer/snapshots/contributed/VBComDlg/api.json index a393fe1c..eba66c37 100644 --- a/indexer/snapshots/contributed/VBComDlg/api.json +++ b/indexer/snapshots/contributed/VBComDlg/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "VBComDlg", "project": "VBComDlg", - "version": "1.0.3.0", + "version": "1.0.13.0", "types": [ { "name": "CommonDialog", @@ -300,6 +300,7 @@ {"name":"CommonDialogFRBufferFindWhat","kind":"field","vis":"private","signature":"Private CommonDialogFRBufferFindWhat As String"}, {"name":"CommonDialogFRBufferReplaceWith","kind":"field","vis":"private","signature":"Private CommonDialogFRBufferReplaceWith As String"}, {"name":"CommonDialogFRDialogHandle","kind":"field","vis":"private","signature":"Private CommonDialogFRDialogHandle As LongPtr"}, + {"name":"CommonDialogFRFallbackOwner","kind":"field","vis":"private","signature":"Private CommonDialogFRFallbackOwner As LongPtr"}, {"name":"CommonDialogFileOKMsg","kind":"field","vis":"private","signature":"Private CommonDialogFileOKMsg As Long"}, {"name":"CommonDialogFindMsg","kind":"field","vis":"private","signature":"Private CommonDialogFindMsg As Long"}, {"name":"CommonDialogHelpMsg","kind":"field","vis":"private","signature":"Private CommonDialogHelpMsg As Long"}, @@ -309,6 +310,7 @@ {"name":"Copies","kind":"property","vis":"public","signature":"Public Property Get Copies() As Integer","returnType":"Integer","accessor":"Get"}, {"name":"Copies","kind":"property","vis":"public","signature":"Public Property Let Copies(ByVal Value As Integer)","accessor":"Let"}, {"name":"CopyMemory","kind":"sub","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Sub CopyMemory Lib \"kernel32\" Alias \"RtlMoveMemory\" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)"},{"cond":"Not (VBA7)","signature":"Private Declare Sub CopyMemory Lib \"kernel32\" Alias \"RtlMoveMemory\" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)"}]}, + {"name":"CreateWindowEx","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function CreateWindowEx Lib \"user32\" Alias \"CreateWindowExW\" (ByVal dwExStyle As Long, ByVal lpClassName As LongPtr, ByVal lpWindowName As LongPtr, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As LongPtr, ByVal hMenu As LongPtr, ByVal hInstance As LongPtr, ByRef lpParam As Any) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Private Declare Function CreateWindowEx Lib \"user32\" Alias \"CreateWindowExW\" (ByVal dwExStyle As Long, ByVal lpClassName As Long, ByVal lpWindowName As Long, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, ByRef lpParam As Any) As Long","returnType":"Long"}]}, {"name":"CustomColors","kind":"property","vis":"public","signature":"Public Property Get CustomColors() As Variant","returnType":"Variant","accessor":"Get"}, {"name":"CustomColors","kind":"property","vis":"public","signature":"Public Property Let CustomColors(ByVal ArgList As Variant)","accessor":"Let"}, {"name":"DEFAULT_QUALITY","kind":"const","vis":"private","signature":"Private Const DEFAULT_QUALITY As Long = 0"}, @@ -330,6 +332,7 @@ {"name":"DefaultExt","kind":"property","vis":"public","signature":"Public Property Get DefaultExt() As String","returnType":"String","accessor":"Get"}, {"name":"DefaultExt","kind":"property","vis":"public","signature":"Public Property Let DefaultExt(ByVal Value As String)","accessor":"Let"}, {"name":"DeleteObject","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function DeleteObject Lib \"gdi32\" (ByVal hObject As LongPtr) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function DeleteObject Lib \"gdi32\" (ByVal hObject As Long) As Long"}]}, + {"name":"DestroyWindow","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function DestroyWindow Lib \"user32\" (ByVal hWnd As LongPtr) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function DestroyWindow Lib \"user32\" (ByVal hWnd As Long) As Long"}]}, {"name":"DialogTitle","kind":"property","vis":"public","signature":"Public Property Get DialogTitle() As String","returnType":"String","accessor":"Get"}, {"name":"DialogTitle","kind":"property","vis":"public","signature":"Public Property Let DialogTitle(ByVal Value As String)","accessor":"Let"}, {"name":"DocumentProperties","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function DocumentProperties Lib \"winspool.drv\" Alias \"DocumentPropertiesW\" (ByVal hWnd As LongPtr, ByVal hPrinter As LongPtr, ByVal lpszDeviceName As LongPtr, ByVal lpDevModeOutput As LongPtr, ByVal lpDevModeInput As LongPtr, ByVal fMode As Long) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function DocumentProperties Lib \"winspool.drv\" Alias \"DocumentPropertiesW\" (ByVal hWnd As Long, ByVal hPrinter As Long, ByVal lpszDeviceName As Long, ByVal lpDevModeOutput As Long, ByVal lpDevModeInput As Long, ByVal fMode As Long) As Long"}]}, @@ -461,7 +464,7 @@ {"name":"IsWindow","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function IsWindow Lib \"user32\" (ByVal hWnd As LongPtr) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function IsWindow Lib \"user32\" (ByVal hWnd As Long) As Long"}]}, {"name":"LF_FACESIZE","kind":"const","vis":"private","signature":"Private Const LF_FACESIZE As Long = 32"}, {"name":"LoWord","kind":"function","vis":"private","signature":"Private Function LoWord(ByVal DWord As Long) As Integer","returnType":"Integer"}, - {"name":"LoadLibrary","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function LoadLibrary Lib \"kernel32\" Alias \"LoadLibraryW\" (ByVal lpLibFileName As LongPtr) As LongPTr","returnType":"LongPTr"},{"cond":"Not (VBA7)","signature":"Private Declare Function LoadLibrary Lib \"kernel32\" Alias \"LoadLibraryW\" (ByVal lpLibFileName As Long) As Long","returnType":"Long"}]}, + {"name":"LoadLibrary","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function LoadLibrary Lib \"kernel32\" Alias \"LoadLibraryW\" (ByVal lpLibFileName As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Private Declare Function LoadLibrary Lib \"kernel32\" Alias \"LoadLibraryW\" (ByVal lpLibFileName As Long) As Long","returnType":"Long"}]}, {"name":"MAXINT_2","kind":"const","vis":"private","signature":"Private Const MAXINT_2 As Integer = 32767"}, {"name":"MAX_PATH","kind":"const","vis":"private","signature":"Private Const MAX_PATH As Long = 260"}, {"name":"Max","kind":"property","vis":"public","signature":"Public Property Get Max() As Long","returnType":"Long","accessor":"Get"}, @@ -680,6 +683,7 @@ {"name":"ToPage","kind":"property","vis":"public","signature":"Public Property Get ToPage() As Long","returnType":"Long","accessor":"Get"}, {"name":"ToPage","kind":"property","vis":"public","signature":"Public Property Let ToPage(ByVal Value As Long)","accessor":"Let"}, {"name":"UnsignedAdd","kind":"function","vis":"private","signature":"Private Function UnsignedAdd(ByVal Start As LongPtr, ByVal Incr As LongPtr) As LongPtr","returnType":"LongPtr"}, + {"name":"WM_CLOSE","kind":"const","vis":"private","signature":"Private Const WM_CLOSE As Long = &H10"}, {"name":"WM_COMMAND","kind":"const","vis":"private","signature":"Private Const WM_COMMAND As Long = &H111"}, {"name":"WM_INITDIALOG","kind":"const","vis":"private","signature":"Private Const WM_INITDIALOG As Long = &H110"}, {"name":"WM_NOTIFY","kind":"const","vis":"private","signature":"Private Const WM_NOTIFY As Long = &H4E"}, @@ -1489,6 +1493,8 @@ {"name":"CdlCCCallbackProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlCCCallbackProc(ByVal hDlg As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlCCCallbackProc(ByVal hDlg As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, {"name":"CdlCFCallbackProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlCFCallbackProc(ByVal hDlg As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlCFCallbackProc(ByVal hDlg As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, {"name":"CdlDefaultProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlDefaultProc(ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlDefaultProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, + {"name":"CdlDisabledThreadWindows","kind":"field","vis":"private","signature":"Private CdlDisabledThreadWindows() As LongPtr"}, + {"name":"CdlDisabledThreadWindowsCount","kind":"field","vis":"private","signature":"Private CdlDisabledThreadWindowsCount As Long"}, {"name":"CdlFR1CallbackProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlFR1CallbackProc(ByVal hDlg As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlFR1CallbackProc(ByVal hDlg As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, {"name":"CdlFR2CallbackProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlFR2CallbackProc(ByVal hDlg As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlFR2CallbackProc(ByVal hDlg As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, {"name":"CdlFRAddHook","kind":"sub","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Sub CdlFRAddHook(ByVal hDlg As LongPtr)"},{"cond":"Not (VBA7)","signature":"Public Sub CdlFRAddHook(ByVal hDlg As Long)"}]}, @@ -1509,12 +1515,16 @@ {"name":"CdlSetSubclass","kind":"sub","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Sub CdlSetSubclass(ByVal hWnd As LongPtr, ByVal This As CommonDialog, ByVal dwRefData As LongPtr, Optional ByVal Name As String)"},{"cond":"Not (VBA7)","signature":"Public Sub CdlSetSubclass(ByVal hWnd As Long, ByVal This As CommonDialog, ByVal dwRefData As Long, Optional ByVal Name As String)"}]}, {"name":"CdlSubclassProc","kind":"function","vis":"public","signatures":[{"cond":"VBA7","signature":"Public Function CdlSubclassProc(ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr, ByVal uIdSubclass As LongPtr, ByVal dwRefData As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Public Function CdlSubclassProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long","returnType":"Long"}]}, {"name":"CdlSubclassProcPtr","kind":"field","vis":"private","signature":"Private CdlSubclassProcPtr As LongPtr"}, + {"name":"CdlTaskModal","kind":"sub","vis":"public","signature":"Public Sub CdlTaskModal()"}, + {"name":"CdlTaskModalEnumThreadWndProc","kind":"function","vis":"private","signature":"Private Function CdlTaskModalEnumThreadWndProc(ByVal hWnd As LongPtr, ByVal lParam As LongPtr) As Long","returnType":"Long"}, {"name":"CoTaskMemAlloc","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function CoTaskMemAlloc Lib \"ole32\" (ByVal cBytes As Long) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Private Declare Function CoTaskMemAlloc Lib \"ole32\" (ByVal cBytes As Long) As Long","returnType":"Long"}]}, {"name":"CoTaskMemFree","kind":"sub","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Sub CoTaskMemFree Lib \"ole32\" (ByVal hMem As LongPtr)"},{"cond":"Not (VBA7)","signature":"Private Declare Sub CoTaskMemFree Lib \"ole32\" (ByVal hMem As Long)"}]}, {"name":"CopyMemory","kind":"sub","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Sub CopyMemory Lib \"kernel32\" Alias \"RtlMoveMemory\" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)"},{"cond":"Not (VBA7)","signature":"Private Declare Sub CopyMemory Lib \"kernel32\" Alias \"RtlMoveMemory\" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)"}]}, {"name":"DefSubclassProc","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function DefSubclassProc Lib \"comctl32\" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Private Declare Function DefSubclassProc Lib \"comctl32\" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long","returnType":"Long"}]}, {"name":"E_NOINTERFACE","kind":"const","vis":"private","signature":"Private Const E_NOINTERFACE As Long = &H80004002"}, {"name":"E_POINTER","kind":"const","vis":"private","signature":"Private Const E_POINTER As Long = &H80004003"}, + {"name":"EnableWindow","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function EnableWindow Lib \"user32\" (ByVal hWnd As LongPtr, ByVal fEnable As Long) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function EnableWindow Lib \"user32\" (ByVal hWnd As Long, ByVal fEnable As Long) As Long"}]}, + {"name":"EnumThreadWindows","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function EnumThreadWindows Lib \"user32\" (ByVal dwThreadID As Long, ByVal lpfn As LongPtr, ByVal lParam As LongPtr) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function EnumThreadWindows Lib \"user32\" (ByVal dwThreadID As Long, ByVal lpfn As Long, ByVal lParam As Long) As Long"}]}, {"name":"GetProp","kind":"function","vis":"private","declare":true,"signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function GetProp Lib \"user32\" Alias \"GetPropW\" (ByVal hWnd As LongPtr, ByVal lpString As LongPtr) As LongPtr","returnType":"LongPtr"},{"cond":"Not (VBA7)","signature":"Private Declare Function GetProp Lib \"user32\" Alias \"GetPropW\" (ByVal hWnd As Long, ByVal lpString As Long) As Long","returnType":"Long"}]}, {"name":"GetVTableIPDCB","kind":"function","vis":"private","signature":"Private Function GetVTableIPDCB() As LongPtr","returnType":"LongPtr"}, {"name":"IPDCB_AddRef","kind":"function","vis":"private","signature":"Private Function IPDCB_AddRef(ByVal Ptr As LongPtr) As Long","returnType":"Long"}, @@ -1524,6 +1534,7 @@ {"name":"IPDCB_Release","kind":"function","vis":"private","signature":"Private Function IPDCB_Release(ByVal Ptr As LongPtr) As Long","returnType":"Long"}, {"name":"IPDCB_SelectionChange","kind":"function","vis":"private","signature":"Private Function IPDCB_SelectionChange(ByVal Ptr As LongPtr) As Long","returnType":"Long"}, {"name":"IsDialogMessage","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function IsDialogMessage Lib \"user32\" Alias \"IsDialogMessageW\" (ByVal hDlg As LongPtr, ByRef lpMsg As TMSG) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function IsDialogMessage Lib \"user32\" Alias \"IsDialogMessageW\" (ByVal hDlg As Long, ByRef lpMsg As TMSG) As Long"}]}, + {"name":"IsWindowEnabled","kind":"function","vis":"private","declare":true,"returnType":"Long","signatures":[{"cond":"VBA7","signature":"Private Declare PtrSafe Function IsWindowEnabled Lib \"user32\" (ByVal hWnd As LongPtr) As Long"},{"cond":"Not (VBA7)","signature":"Private Declare Function IsWindowEnabled Lib \"user32\" (ByVal hWnd As Long) As Long"}]}, {"name":"NULL_PTR","kind":"const","vis":"private","signatures":[{"cond":"Win64","signature":"Private Const NULL_PTR As LongPtr = 0"},{"cond":"Not (Win64)","signature":"Private Const NULL_PTR As Long = 0"}]}, {"name":"PTR_SIZE","kind":"const","vis":"private","signatures":[{"cond":"Win64","signature":"Private Const PTR_SIZE As Long = 8"},{"cond":"Not (Win64)","signature":"Private Const PTR_SIZE As Long = 4"}]}, {"name":"ProcPtr","kind":"function","vis":"private","signature":"Private Function ProcPtr(ByVal Address As LongPtr) As LongPtr","returnType":"LongPtr"}, diff --git a/test/example-projects/contributed-VBComDlg/Settings b/test/example-projects/contributed-VBComDlg/Settings index d68b4b9c..3b92d017 100644 --- a/test/example-projects/contributed-VBComDlg/Settings +++ b/test/example-projects/contributed-VBComDlg/Settings @@ -51,14 +51,14 @@ "autoCtlExt": true, "id": "{B00CAB91-2215-4123-9768-F33903B4A788}", "licence": "MIT", - "name": "[IMPORTED] CommonDialog class for 32-bit and 64-bit", + "name": "[IMPORTED] VB Common Dialog Class for 32-bit and 64-bit", "path32": "/Packages/VBComDlg", "path64": "/Packages/VBComDlg", "symbolId": "VBComDlg", "versionBuild": "0", "versionMajor": "1", "versionMinor": "0", - "versionRevision": "3" + "versionRevision": "13" } ], "project.settingsVersion": 1, From ea40e526c4e6d41b7671ca198240446e88b679e8 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:10:33 +0200 Subject: [PATCH 13/17] WIP.md: a minor defect the section documents does not make a contributed package Experimental (owner: VBComDlg stays Contributed) --- WIP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WIP.md b/WIP.md index 3388300f..ea1f9dfd 100644 --- a/WIP.md +++ b/WIP.md @@ -79,7 +79,7 @@ The rest of this file is the maintenance guide for updating existing pages or ad > would file the page as a *static file* and serve the raw markdown. Editors on > Windows add a BOM unasked. `lib/frontmatter.mjs` strips a leading BOM before parsing. - `docs/Reference/Built-In/tbIDE/` — IDE Extensibility package (this is the **addin SDK**). The package is type-only — it ships **public interfaces + CoClasses** that an addin DLL binds to; every implementation behind them lives in the twinBASIC IDE itself. The user-facing surface is one entry-point factory (`tbCreateCompilerAddin`) plus 23 CoClasses grouped by role: the addin contract (`AddIn`), the root API (`Host`), the loaded `Project`, the editors collection (`Editor` / `CodeEditor` / `Editors`), the virtual file system (`FileSystem` / `FileSystemItem` / `Folder` / `File`), the in-IDE UI surface (`Toolbar` / `Toolbars` / `Button` / `ToolWindow` / `ToolWindows`), the HTML DOM inside a tool window (`HtmlElement` / `HtmlElements` / `HtmlElementProperty` / `HtmlElementProperties` / `HtmlEventProperty` / `HtmlEventProperties`), the `DebugConsole`, `KeyboardShortcuts`, `Themes`, and the single concrete user-instantiable helper class `AddinTimer`. Flat layout — one page per CoClass / Class plus the index landing. -- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner, 2026-10-12). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. +- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner, 2026-10-12). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12); a minor defect that the section documents does not make it Experimental (owner, 2026-10-12: VBComDlg, whose Replace All raises no event, stays Contributed): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. - `docs/Reference/Statements.md` — alphabetical index of language statements. - `docs/Reference/Procedures and Functions.md` — alphabetical index of procedures/functions. - `docs/LLVM/` — the LLVM section: compiling with the LLVM back end. A top-level section between Features and Reference Section in the nav, at `nav_order: 6` (Features is 5). `index.md` is the landing page and `Getting-Started.md` the only page so far, with its screenshots under `Images/`. Everything it describes arrived in **BETA 984**. Its language claims are measured on BETA 995 with `tbrun --llvm` and `--exe`: the comma, space and comma-space spellings of `[CompilerOptions]` all turn LLVM and `+optimize` on, `[CompilerOptions("")]` turns it off under project-wide LLVM, the long CPU-flag sample runs, and an error is lost between procedures when either the callee or the caller is LLVM-compiled. Its samples are marked `check_build`, which compiles them; `examples.bat --llvm` also builds them with LLVM. From b85cb4224ffb4406593348d366becab9359bff48 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:20:40 +0200 Subject: [PATCH 14/17] WIP.md: a package moves from Contributed to Experimental for its defects only once a separate agent has confirmed them (owner) --- WIP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WIP.md b/WIP.md index ea1f9dfd..49838ec5 100644 --- a/WIP.md +++ b/WIP.md @@ -79,7 +79,7 @@ The rest of this file is the maintenance guide for updating existing pages or ad > would file the page as a *static file* and serve the raw markdown. Editors on > Windows add a BOM unasked. `lib/frontmatter.mjs` strips a leading BOM before parsing. - `docs/Reference/Built-In/tbIDE/` — IDE Extensibility package (this is the **addin SDK**). The package is type-only — it ships **public interfaces + CoClasses** that an addin DLL binds to; every implementation behind them lives in the twinBASIC IDE itself. The user-facing surface is one entry-point factory (`tbCreateCompilerAddin`) plus 23 CoClasses grouped by role: the addin contract (`AddIn`), the root API (`Host`), the loaded `Project`, the editors collection (`Editor` / `CodeEditor` / `Editors`), the virtual file system (`FileSystem` / `FileSystemItem` / `Folder` / `File`), the in-IDE UI surface (`Toolbar` / `Toolbars` / `Button` / `ToolWindow` / `ToolWindows`), the HTML DOM inside a tool window (`HtmlElement` / `HtmlElements` / `HtmlElementProperty` / `HtmlElementProperties` / `HtmlEventProperty` / `HtmlEventProperties`), the `DebugConsole`, `KeyboardShortcuts`, `Themes`, and the single concrete user-instantiable helper class `AddinTimer`. Flat layout — one page per CoClass / Class plus the index landing. -- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner, 2026-10-12). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12); a minor defect that the section documents does not make it Experimental (owner, 2026-10-12: VBComDlg, whose Replace All raises no event, stays Contributed): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. +- `docs/Reference/Contributed/` — the contributed packages, one folder each, landing page `Contributed.md` beside it. **A package's landing page opens, under its H1, with `**Author:**`** (owner, 2026-10-11): the publisher TWINSERV lists (`publisher` in `indexer/.packages/manifests/contributed.json`), or the author the package's own sources name when that is someone else (VBA_JSON: Tim Hall, published by WaynePhillipsEA). Next to the author, on the same line, `**Version:**`: the version the section documents, which is its `indexed_from` and changes with it (owner, 2026-10-12). Then `**On GitHub:**` with a link, when a repository holds the package, or the library the package says it is made from; search GitHub for the package's name and the author's account, and check that the repository holds the package's code (its history too: `TBMANLIB_*` were never in woeoio's `tbman`). A landing page with one or two sections has no `* TOC` list. A class with member pages is a folder, `/index.md` at `/tB/Packages/Contributed///` with its members beside it, so a member links to its class as `(.)`; a class documented on one page is `.md`. Each package is a chapter of the book's Packages part in `_book.yml`. A section's `indexed_from` is the four-part TWINSERV version, and its snapshot is under `indexer/snapshots/contributed/`. Its samples compile in the `contributed-` sample template, whose `Settings` names the package's version: **change that version with `indexed_from`** ([WIP.ExamplesBuild.md](WIP.ExamplesBuild.md#template-projects)). **A contributed package is documented and its samples compiled against the newest twinBASIC BETA installed, never an older one** (owner, 2026-10-11): the version that matters is the package's, and a statement about the compiler (such as "does not compile on BETA 1005") names that newest build. **A contributed package that does not compile on that build, or has defects that a program would meet, is listed under Experimental Packages** (owner, 2026-10-12); a minor defect that the section documents does not make it Experimental (owner, 2026-10-12: VBComDlg, whose Replace All raises no event, stays Contributed). **A package moves from Contributed to Experimental for its defects only after a separate agent has reproduced each defect independently** and ruled out misuse, a wrong expectation, a twinBASIC defect and the harness (owner, 2026-10-12): `docs/Reference/Experimental.md`, at `/tB/Packages/Experimental/`, after Contributed Packages. Its landing page's `parent:` is `Experimental Packages`, its line is in `Experimental.md` and not in `Contributed.md`, and its book chapter follows the Experimental Packages chapter. Its folder and URLs stay under `Contributed/`, so a package that is fixed moves back by changing only those three, and its pages keep their addresses. - `docs/Reference/Statements.md` — alphabetical index of language statements. - `docs/Reference/Procedures and Functions.md` — alphabetical index of procedures/functions. - `docs/LLVM/` — the LLVM section: compiling with the LLVM back end. A top-level section between Features and Reference Section in the nav, at `nav_order: 6` (Features is 5). `index.md` is the landing page and `Getting-Started.md` the only page so far, with its screenshots under `Images/`. Everything it describes arrived in **BETA 984**. Its language claims are measured on BETA 995 with `tbrun --llvm` and `--exe`: the comma, space and comma-space spellings of `[CompilerOptions]` all turn LLVM and `+optimize` on, `[CompilerOptions("")]` turns it off under project-wide LLVM, the long CPU-flag sample runs, and an error is lost between procedures when either the callee or the caller is LLVM-compiled. Its samples are marked `check_build`, which compiles them; `examples.bat --llvm` also builds them with LLVM. From bf33296248e9883a22b1f03b2228144f686f966e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:22:51 +0200 Subject: [PATCH 15/17] tbRegExp: moved to 1.4.0.0: its error texts and numbers, group names, literal ] and }, the last group of a duplicate name, Err kept after a failed compile; WARNING on repeated empty matches with Global, NOTE on IsValid --- .../Contributed/tbRegExp/RegExp/Execute.md | 12 +++++++++ .../Contributed/tbRegExp/RegExp/IsValid.md | 9 ++++++- .../Contributed/tbRegExp/RegExp/LastError.md | 5 +++- .../tbRegExp/RegExp/LastErrorNumber.md | 16 +++++++++++- .../Contributed/tbRegExp/RegExp/Pattern.md | 2 +- .../Contributed/tbRegExp/RegExp/Replace.md | 13 ++++++++++ .../Contributed/tbRegExp/RegExp/Split.md | 16 ++++++++++++ .../Contributed/tbRegExp/RegExp/index.md | 2 +- .../Contributed/tbRegExp/SubMatches/Item.md | 14 +++++++++- docs/Reference/Contributed/tbRegExp/index.md | 26 ++++++++++++++++--- .../snapshots/contributed/tbRegExp/api.json | 11 +++++--- .../contributed-tbRegExp/Settings | 4 +-- 12 files changed, 114 insertions(+), 16 deletions(-) diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md index a3ff8c54..e600a7f4 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md @@ -26,6 +26,18 @@ With [**Global**](Global) set to **False**, the collection holds at most one mat [**IgnoreCase**](IgnoreCase), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) change what counts as a match. +> [!WARNING] +> With **Global** set to **True**, a match of no characters is returned twice when the search had to skip at least one character to reach it, so the collection holds one **Match** too many at each such position. A pattern that can match no characters is affected: `$`, `\b`, `^` with **MultiLine** set to **True**, and a lookahead or lookbehind on its own. VBScript's **RegExp** returns each such match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. + +The pattern in this example matches no characters, before each capital letter. `fooBarBaz` has two capitals, and the collection holds four matches. + +```tb check_build check_run +Dim re As New RegExp +re.Global = True +re.Pattern = "(?=[A-Z])" +Debug.Print re.Execute("fooBarBaz").Count ' 4 +``` + Each **Match** gives the matched text ([**Value**](../Match/Value)), the position where it starts ([**FirstIndex**](../Match/FirstIndex), counted from 0), its length, and the text of each group of the pattern ([**SubMatches**](../Match/SubMatches)). A group written `(?...)` can be read by its name. An invalid pattern raises the compile error, with the number in [**LastErrorNumber**](LastErrorNumber) and the description in [**LastError**](LastError). Check [**IsValid**](IsValid) first to avoid it. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md index a1c03884..77845a75 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md @@ -23,13 +23,20 @@ The property compiles the pattern if it has not been compiled since [**Pattern** Check **IsValid** before [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) or [**Split**](Split) when the pattern comes from outside the program, because each of those raises the compile error. +Although nothing is raised, the compile error of an invalid pattern stays in the **Err** object after the call that compiled the pattern returns. A program that tests **Err** for other errors calls **Err.Clear** first. + +> [!NOTE] +> Two faults are not found when the pattern is compiled, so **IsValid** returns **True** for them: a quantifier whose lower count is above its upper count, such as `a{2,1}`, and a backreference to a group that the pattern does not have, such as `(a)\2`. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise error 3000 when they use the pattern, with the description that Windows gives that number, *The specified print monitor is unknown.* This is how version 1.4.0.0 behaves. + ## Example ```tb check_build check_run Dim re As RegExp Set re = New RegExp re.Pattern = "(\d+" -Debug.Print re.IsValid ' False +Debug.Print re.IsValid ' False +Debug.Print Err.Number = re.LastErrorNumber ' True +Err.Clear re.Pattern = "(\d+)" Debug.Print re.IsValid ' True diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md b/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md index d8c32c4a..c0f5dbbf 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/LastError.md @@ -19,7 +19,7 @@ Returns a **String**: the description of the compile error, or an empty string w ## Remarks -The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastError** raises nothing. The text is the `Description` of the error that the compilation raised; [**LastErrorNumber**](LastErrorNumber) is its number. +The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastError** raises nothing, but the error stays in the **Err** object (see [**IsValid**](IsValid)). The text is a sentence that names the fault, such as *Unterminated character class: a '[' without a matching ']'.* for the pattern `[abc`. [**LastErrorNumber**](LastErrorNumber) is the number of the error and lists the faults. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise an error with this description when the pattern is invalid. @@ -35,6 +35,9 @@ re.Pattern = "(\d+" Debug.Print re.IsValid ' False Debug.Print Len(re.LastError) > 0 ' True +re.Pattern = "[abc" +Debug.Print re.LastError ' Unterminated character class: a '[' without a matching ']'. + On Error Resume Next re.Test "123" Debug.Print Err.Description = re.LastError ' True diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md b/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md index 84c2ffd6..2a4103bc 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/LastErrorNumber.md @@ -21,7 +21,21 @@ Returns a **Long**: the number of the compile error, or 0 when the pattern is va The property compiles the pattern if it has not been compiled since [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) last changed. The compilation traps its error, so **LastErrorNumber** raises nothing. The value is the `Number` of the error that the compilation raised; [**LastError**](LastError) is its description. -The engine raises its pattern errors with numbers of the form `vbObjectError + 3000 + n`, where *n* identifies the fault, as in the example. +The engine raises its pattern errors with numbers of the form `vbObjectError + 3000 + n`, where *n* identifies the fault, as in the example. The compilation traps the error, so **LastErrorNumber** raises nothing, but the error stays in the **Err** object (see [**IsValid**](IsValid)). + +| *n* | Fault | Example | +|-----|-------|---------| +| 1 | An escape the engine does not know, or a backslash at the end | `\k`, `\A`, `\p{L}`, `\` | +| 2 | A `\x` or `\u` escape without its hexadecimal digits | `\u00` | +| 3 | A range in a character class that runs backwards | `[z-a]` | +| 4 | A character class without its `]` | `[abc` | +| 6 | A group construct `(?<` that is neither a lookbehind nor a valid name | `(?<1a>x)` | +| 8 | A `{` that does not start a quantifier, or a count that is too large | `a{2` | +| 9 | A group without its `)` | `(\d+` | +| 11 | A `)` that closes no group | `)` | +| 12 | A quantifier with nothing to repeat | `*a` | +| 13 | A group name with a character that a name cannot hold | `(?x)` | +| 14 | An inline option that is not `i`, `m` or `s`, which includes an atomic group and a conditional | `(?x)`, `(?>a)` | [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise an error with this number when the pattern is invalid. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md b/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md index 887d412c..b14a1210 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Pattern.md @@ -34,7 +34,7 @@ Syntax: *object*.**Pattern** **=** *value* Setting a different pattern makes it compile again the next time it is needed. Setting the current pattern does nothing. A pattern that does not compile raises no error when it is set: [**IsValid**](IsValid), [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) report the failure, and [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) raise it. -A named group is written `(?...)`. Its text is read from the [**SubMatches**](../SubMatches/) of a [**Match**](../Match/) by name, and used in [**Replace**](Replace) as `$`. +A named group is written `(?...)`. Its text is read from the [**SubMatches**](../SubMatches/) of a [**Match**](../Match/) by name, and used in [**Replace**](Replace) as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores. The [overview of the package](../#pattern-syntax) lists the other differences from VBScript's pattern syntax. ## Example diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md b/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md index b709e6fe..0801bf38 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Replace.md @@ -46,6 +46,19 @@ A `$` at the end of *replaceString*, or followed by a character that is not in t With [**Global**](Global) set to **False**, only the first match is replaced. With **Global** set to **True**, every match is. [**IgnoreCase**](IgnoreCase), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) change what counts as a match. +> [!WARNING] +> With **Global** set to **True**, the replacement is made twice at a position where a match of no characters was reached by skipping at least one character, such as the start of every line but the first with `^` and **MultiLine** set to **True**. The warning at [**Execute**](Execute#remarks) lists the patterns affected. VBScript's **RegExp** makes the replacement once. This is how version 1.4.0.0 behaves. + +In this example the pattern `^` is meant to put `> ` at the start of each of three lines. The second and third lines get it twice. + +```tb check_build check_run +Dim re As New RegExp +re.Global = True +re.MultiLine = True +re.Pattern = "^" +Debug.Print Replace(re.Replace("a" & vbLf & "b" & vbLf & "c", "> "), vbLf, "/") ' > a/> > b/> > c +``` + An invalid pattern raises the compile error, with the number in [**LastErrorNumber**](LastErrorNumber) and the description in [**LastError**](LastError). Check [**IsValid**](IsValid) first to avoid it. ## Example diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Split.md b/docs/Reference/Contributed/tbRegExp/RegExp/Split.md index f3d7f367..3796e21b 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Split.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Split.md @@ -30,6 +30,22 @@ When [**Pattern**](Pattern) finds no match, the collection holds one item, the w [**IgnoreCase**](IgnoreCase), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) apply to the matching. +> [!WARNING] +> With **Global** set to **True**, a match of no characters that was reached by skipping at least one character splits the string twice, which adds an empty string to the collection. The warning at [**Execute**](Execute#remarks) lists the patterns affected. VBScript's **RegExp** has no **Split**, and its **Execute** reports such a match once. This is how version 1.4.0.0 behaves. + +In this example the string is to be split before each capital letter. The result holds an empty string between `foo` and `Bar`, and between `Bar` and `Baz`. + +```tb check_build check_run +Dim re As New RegExp +re.Global = True +re.Pattern = "(?=[A-Z])" + +Dim parts As Collection +Set parts = re.Split("fooBarBaz") +Debug.Print parts.Count ' 5 +Debug.Print parts(1) & "|" & parts(2) & "|" & parts(3) & "|" & parts(4) & "|" & parts(5) ' foo||Bar||Baz +``` + When **Pattern** is not a valid regular expression, **Split** raises the compile error. Its number is [**LastErrorNumber**](LastErrorNumber), its description is [**LastError**](LastError), and its source is `RegExp`. Read [**IsValid**](IsValid) first to avoid the error. ## Example diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/index.md b/docs/Reference/Contributed/tbRegExp/RegExp/index.md index 6db97689..a2789822 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/index.md @@ -47,7 +47,7 @@ All four are **False** in a new instance. The pattern is compiled the first time a method or one of [**IsValid**](IsValid), [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) needs it. It is compiled again after [**Pattern**](Pattern) or [**IgnoreCase**](IgnoreCase) is set to a different value. [**Global**](Global), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) are applied when a match is made and do not cause a new compilation. -A pattern that does not compile does not raise an error at once. [**IsValid**](IsValid) returns **False**, and [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) describe the failure. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise that error, with the number in **LastErrorNumber**, the description in **LastError** and the source `RegExp`. +A pattern that does not compile does not raise an error at once. [**IsValid**](IsValid) returns **False**, and [**LastError**](LastError) and [**LastErrorNumber**](LastErrorNumber) describe the failure. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise that error, with the number in **LastErrorNumber**, the description in **LastError** and the source `RegExp`. When **IsValid**, **LastError** or **LastErrorNumber** is the call that compiles an invalid pattern, it raises nothing, but the compile error stays in the **Err** object after it returns; [**IsValid**](IsValid) says what to do about it. ## Properties diff --git a/docs/Reference/Contributed/tbRegExp/SubMatches/Item.md b/docs/Reference/Contributed/tbRegExp/SubMatches/Item.md index 586e53bb..a8863f85 100644 --- a/docs/Reference/Contributed/tbRegExp/SubMatches/Item.md +++ b/docs/Reference/Contributed/tbRegExp/SubMatches/Item.md @@ -29,7 +29,9 @@ Returns a **String**. The property is read-only. A position below 0, or not below [**Count**](Count), raises run-time error `vbObjectError + 9` with the message *Requested item not found in SubMatches collection*. -A name is the one given to a group in the pattern, written `(?...)`. **Item** returns the string of the first group that has that name. Letter case counts: `sm("YEAR")` does not find a group named `year`. A name that no group has returns an empty string and raises no error. +A name is the one given to a group in the pattern, written `(?...)`. **Item** returns the string of the group that has that name. Letter case counts: `sm("YEAR")` does not find a group named `year`. A name that no group has returns an empty string and raises no error. A name starts with a letter or an underscore and goes on with letters, digits and underscores. + +When several groups have the same name, **Item** returns the string of the last of them that took part in the match, as the last example shows. An empty result has three possible causes: a group that took no part in the match, a group that captured no characters, and a name that no group has. @@ -66,6 +68,16 @@ Debug.Print sm(1) Debug.Print Err.Number & ": " & Err.Description ' -2147221495: Requested item not found in SubMatches collection ``` +This example gives two groups the same name. In `ab` both groups took part, so the second one is returned. In `a` only the first group did. + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "(?a)(?b)?" + +Debug.Print re.Execute("ab")(0).SubMatches("n") ' b +Debug.Print re.Execute("a")(0).SubMatches("n") ' a +``` + ## See Also - [Count](Count) property -- the number of strings diff --git a/docs/Reference/Contributed/tbRegExp/index.md b/docs/Reference/Contributed/tbRegExp/index.md index 7c53c8dd..6fd51c3a 100644 --- a/docs/Reference/Contributed/tbRegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/index.md @@ -4,14 +4,14 @@ parent: Contributed Packages has_toc: false exclude_from_docs: - StaticRegex -indexed_from: 1.0.5.0 +indexed_from: 1.4.0.0 permalink: /tB/Packages/Contributed/tbRegExp/ --- # tbRegExp Package {: .no_toc } -**Author:** GCuser99. **Version:** 1.0.5.0. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. +**Author:** GCuser99. **Version:** 1.4.0.0. **On GitHub:** [GCuser99/tbRegExp](https://github.com/GCuser99/tbRegExp), in the folder *Package*. The **tbRegExp** contributed package provides regular expressions for twinBASIC projects, as a replacement for the **RegExp** object of VBScript. It follows the same object model. A [**RegExp**](RegExp/) is given a pattern and options, its [**Execute**](RegExp/Execute) method returns a [**MatchCollection**](MatchCollection/) of [**Match**](Match/) objects, and each **Match** holds the text captured by the groups of the pattern as a [**SubMatches**](SubMatches/) object. Positions are zero-based, as in VBScript. @@ -19,11 +19,14 @@ The matching is done by the [vba-regex](https://github.com/sihlfall/vba-regex) e Beyond VBScript's object, **RegExp** has the [**DotAll**](RegExp/DotAll) and [**Flags**](RegExp/Flags) options, the [**Split**](RegExp/Split) method, and [**IsValid**](RegExp/IsValid), [**LastError**](RegExp/LastError) and [**LastErrorNumber**](RegExp/LastErrorNumber), which report an invalid pattern before it is used. [**Replace**](RegExp/Replace) reads a `$` in the replacement string differently from VBScript. +> [!WARNING] +> With [**Global**](RegExp/Global) set to **True**, a match of no characters is reported twice when the search had to skip at least one character to reach it. A pattern that can match no characters is affected: `$`, `\b`, `^` with [**MultiLine**](RegExp/MultiLine), and a lookahead or lookbehind on its own. [**Execute**](RegExp/Execute) returns the match twice, [**Replace**](RegExp/Replace) makes its replacement twice and [**Split**](RegExp/Split) adds an extra empty string, and nothing is raised. VBScript's **RegExp** reports such a match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. + ## Pattern syntax A pattern is written as for VBScript's **RegExp**. **tbRegExp** also accepts: -- named groups, `(?...)`: [**SubMatches.Item**](SubMatches/Item) returns one by its name, and [**Replace**](RegExp/Replace) inserts one as `$`; +- named groups, `(?...)`: [**SubMatches.Item**](SubMatches/Item) returns one by its name, and [**Replace**](RegExp/Replace) inserts one as `$`. A name starts with a letter or an underscore and goes on with letters, digits and underscores; a pattern with any other name is not valid; - lookbehind, `(?<=...)` and `(?`, `\A`, `\Z`, `\p{...}`, an atomic group `(?>...)` or a conditional is not valid: [**IsValid**](RegExp/IsValid) returns **False**. A numbered backreference such as `\1` works. `\w` matches only the ASCII letters and digits and `_`, as in VBScript, so `\w+` finds `caf` in `café`. +A pattern that holds `\k`, `\A`, `\Z`, `\p{...}`, an atomic group `(?>...)` or a conditional is not valid: [**IsValid**](RegExp/IsValid) returns **False**. A numbered backreference such as `\1` works when the pattern has that group; [**IsValid**](RegExp/IsValid) does not find a backreference to a group that is missing. `\w` matches only the ASCII letters and digits and `_`, as in VBScript, so `\w+` finds `caf` in `café`. + +A `{` has to start a quantifier: `{n}`, `{n,}`, `{n,m}` or `{,m}`, which means `{0,m}`. A pattern in which a `{` starts none, such as `a{` or `a{x}`, is not valid; write `\{` for the character. VBScript reads a `{` that starts no quantifier, and `{,m}`, as ordinary text. A `]` or `}` that closes nothing is an ordinary character, as in VBScript. + +```tb check_build check_run +Dim re As New RegExp +re.Pattern = "(?<_part2>\d)" +Debug.Print re.IsValid ' True +re.Pattern = "(?<2part>\d)" +Debug.Print re.IsValid ' False + +re.Pattern = "a{x}" +Debug.Print re.IsValid ' False +re.Pattern = "a\{x}" +Debug.Print re.Execute("a{x}")(0).Value ' a{x} +``` ## Classes diff --git a/indexer/snapshots/contributed/tbRegExp/api.json b/indexer/snapshots/contributed/tbRegExp/api.json index e0c67cb2..f6296c2a 100644 --- a/indexer/snapshots/contributed/tbRegExp/api.json +++ b/indexer/snapshots/contributed/tbRegExp/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "tbRegExp", "project": "tbRegExp", - "version": "1.0.5.0", + "version": "1.4.0.0", "types": [ { "name": "Match", @@ -39,7 +39,7 @@ {"name":"Count","kind":"property","vis":"public","signature":"Public Property Get Count() As Long","returnType":"Long","accessor":"Get","description":"Returns the number of Match objects found in the source string."}, {"name":"Internal_Add","kind":"sub","vis":"friend","signature":"Friend Sub Internal_Add(obj As Match)"}, {"name":"Item","kind":"property","vis":"public","signature":"Public Property Get Item(ByVal pItemIndex As Variant) As Match","returnType":"Match","accessor":"Get","attrs":[{"name":"DefaultMember"}],"description":"Returns the Match object associated with the provided index"}, - {"name":"NewEnum","kind":"function","vis":"public","signature":"Public Function NewEnum() As IUnknown","returnType":"IUnknown","hidden":true,"attrs":[{"name":"Hidden","args":"True"},{"name":"Enumerator"}]}, + {"name":"NewEnum","kind":"function","vis":"public","signature":"Public Function NewEnum() As IUnknown","returnType":"IUnknown","hidden":true,"attrs":[{"name":"Hidden"},{"name":"Enumerator"}]}, {"name":"colMatches","kind":"field","vis":"private","signature":"Private colMatches As Collection"} ] }, @@ -53,9 +53,11 @@ "description": "This class exposes a drop-in replacement for VBSript's regular expressions object model.", "members": [ {"name":"Class_Initialize","kind":"sub","vis":"private","signature":"Private Sub Class_Initialize()"}, + {"name":"DescribeRegexError","kind":"function","vis":"private","signature":"Private Function DescribeRegexError(ByVal errNum As Long) As String","returnType":"String"}, {"name":"DotAll","kind":"property","vis":"public","signature":"Public Property Let DotAll(ByVal pDotAll As Boolean)","accessor":"Let","description":"If 'True', '.' pattern will match across new line charactors. Defaults to 'False'"}, {"name":"DotAll","kind":"property","vis":"public","signature":"Public Property Get DotAll() As Boolean","returnType":"Boolean","accessor":"Get"}, {"name":"EnsureCompiled","kind":"sub","vis":"private","signature":"Private Sub EnsureCompiled()"}, + {"name":"ErrText","kind":"function","vis":"private","signature":"Private Function ErrText(ByVal errNum As Long, ByVal fallback As String) As String","returnType":"String"}, {"name":"Execute","kind":"function","vis":"public","signature":"Public Function Execute(ByVal sourceString As String) As MatchCollection","returnType":"MatchCollection","description":"Returns a MatchCollection. Uses the Pattern property to search the sourceString."}, {"name":"Flags","kind":"property","vis":"public","signature":"Public Property Let Flags(ByVal pFlags As String)","accessor":"Let","description":"Sets or Gets the options in use: g-global; m-multiline; i-ignore case; s-dot all. Example: 'gm' sets Global and MultiLine to 'True', IgnoreCase and DotAll to 'False'."}, {"name":"Flags","kind":"property","vis":"public","signature":"Public Property Get Flags() As String","returnType":"String","accessor":"Get"}, @@ -72,7 +74,7 @@ {"name":"Pattern","kind":"property","vis":"public","signature":"Public Property Let Pattern(ByVal pPattern As String)","accessor":"Let","description":"The regular expression pattern."}, {"name":"Pattern","kind":"property","vis":"public","signature":"Public Property Get Pattern() As String","returnType":"String","accessor":"Get"}, {"name":"Replace","kind":"function","vis":"public","signature":"Public Function Replace(ByVal sourceString As String, ByVal replaceString As String) As String","returnType":"String","description":"Replaces matches with replaceString and returns the String with replacements made."}, - {"name":"Split","kind":"function","vis":"public","signature":"Public Function Split(ByVal sourceString As String) As Collection","returnType":"Collection","description":"Splits an input string into an array of substrings at the positions defined by a regular expression match."}, + {"name":"Split","kind":"function","vis":"public","signature":"Public Function Split(ByVal sourceString As String) As Collection","returnType":"Collection","description":"Splits an input string into an array of substrings at the positions defined by a regular expression match. Needs Global Property set to 'True'."}, {"name":"Test","kind":"function","vis":"public","signature":"Public Function Test(ByVal sourceString As String) As Boolean","returnType":"Boolean","description":"Returns 'True' if Pattern finds a match in sourceString, otherwise returns 'False'."}, {"name":"mCompileAttempted","kind":"field","vis":"private","signature":"Private mCompileAttempted As Boolean"}, {"name":"mDotAll","kind":"field","vis":"private","signature":"Private mDotAll As Boolean"}, @@ -141,6 +143,7 @@ {"name":"InitializeUnicodeCanonLookupTable","kind":"sub","vis":"private","signature":"Private Sub InitializeUnicodeCanonLookupTable(ByRef t() As Long)"}, {"name":"InitializeUnicodeCanonRunsTable","kind":"sub","vis":"private","signature":"Private Sub InitializeUnicodeCanonRunsTable(ByRef t() As Long)"}, {"name":"IsIdentifierChar","kind":"function","vis":"private","signature":"Private Function IsIdentifierChar(ByVal c As Long) As Boolean","returnType":"Boolean"}, + {"name":"IsIdentifierStart","kind":"function","vis":"private","signature":"Private Function IsIdentifierStart(ByVal c As Long) As Boolean","returnType":"Boolean"}, {"name":"LEXER_ENDOFINPUT","kind":"const","vis":"private","signature":"Private Const LEXER_ENDOFINPUT As Long = -1"}, {"name":"LexerParseEscapeU","kind":"function","vis":"private","signature":"Private Function LexerParseEscapeU(ByRef lexCtx As LexerContext) As Long","returnType":"Long"}, {"name":"LexerParseEscapeX","kind":"function","vis":"private","signature":"Private Function LexerParseEscapeX(ByRef lexCtx As LexerContext) As Long","returnType":"Long"}, @@ -845,7 +848,7 @@ {"name":"Count","kind":"property","vis":"public","signature":"Public Property Get Count() As Long","returnType":"Long","accessor":"Get","description":"Returns the number of SubMatch objects found in the source string."}, {"name":"Internal_SetData","kind":"sub","vis":"friend","signature":"Friend Sub Internal_SetData(ByRef vals() As String, ByRef keys() As String, ByVal count As Long)"}, {"name":"Item","kind":"property","vis":"public","signature":"Public Property Get Item(ByVal pItemIndex As Variant) As String","returnType":"String","accessor":"Get","attrs":[{"name":"DefaultMember"}],"description":"Returns the SubMatch string associated with the provided index. Named groups are allowed."}, - {"name":"NewEnum","kind":"function","vis":"public","signature":"Public Function NewEnum() As IUnknown","returnType":"IUnknown","hidden":true,"attrs":[{"name":"Hidden","args":"True"},{"name":"Enumerator"}]}, + {"name":"NewEnum","kind":"function","vis":"public","signature":"Public Function NewEnum() As IUnknown","returnType":"IUnknown","hidden":true,"attrs":[{"name":"Hidden"},{"name":"Enumerator"}]}, {"name":"mCap","kind":"field","vis":"private","signature":"Private mCap As Long"}, {"name":"mCount","kind":"field","vis":"private","signature":"Private mCount As Long"}, {"name":"mKeys","kind":"field","vis":"private","signature":"Private mKeys() As String"}, diff --git a/test/example-projects/contributed-tbRegExp/Settings b/test/example-projects/contributed-tbRegExp/Settings index 749ec7f4..52a0f2aa 100644 --- a/test/example-projects/contributed-tbRegExp/Settings +++ b/test/example-projects/contributed-tbRegExp/Settings @@ -57,8 +57,8 @@ "symbolId": "tbRegExp", "versionBuild": "0", "versionMajor": "1", - "versionMinor": "0", - "versionRevision": "5" + "versionMinor": "4", + "versionRevision": "0" } ], "project.settingsVersion": 1, From da4034f48dea93baa32b3f177fff36f1e9a1c772 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:29:45 +0200 Subject: [PATCH 16/17] tbRegExp: listed under Experimental Packages, its repeated empty matches with Global confirmed by a second agent; the callouts made exact --- WIP.md | 2 +- docs/Reference/Contributed.md | 1 - .../Contributed/tbRegExp/RegExp/Execute.md | 2 +- .../Contributed/tbRegExp/RegExp/IsValid.md | 2 +- docs/Reference/Contributed/tbRegExp/index.md | 4 ++-- docs/Reference/Experimental.md | 1 + docs/_book.yml | 14 +++++++------- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/WIP.md b/WIP.md index 49838ec5..013ed45d 100644 --- a/WIP.md +++ b/WIP.md @@ -34,7 +34,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text. TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, tbRegExp, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text, and tbRegExp, with **Global**, reports a match of no characters twice when the search skipped characters to reach it (a defect of the vba-regex engine it is made from, confirmed by a second agent). TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. diff --git a/docs/Reference/Contributed.md b/docs/Reference/Contributed.md index 1f253d71..0fdd593c 100644 --- a/docs/Reference/Contributed.md +++ b/docs/Reference/Contributed.md @@ -22,7 +22,6 @@ Each package is versioned apart from twinBASIC, and its section says which versi - [**TBMANLIB_ListBoxHScroll**](TBMANLIB_ListBoxHScroll/) -- a horizontal scroll bar for a **ListBox** - [**TBMANLIB_RES**](TBMANLIB_RES/) -- resources embedded in an executable, as bytes, strings, hex, Base64 or pictures - [**tbProjPacker**](tbProjPacker/) -- a `.twinproj` or `.twinpack` file unpacked into a folder of source files, and packed again -- [**tbRegExp**](tbRegExp/) -- regular expressions, in place of VBScript's **RegExp** object - [**tsJson**](tsJson/) -- a JSON model with parsing, JSONPath queries, JSON Pointer, JSON Patch and JSON Schema validation - [**tsPwGen**](tsPwGen/) -- passwords, PINs and passphrases, with their entropy known before they are generated - [**TwinTimerLib**](TwinTimerLib/) -- a Win32 timer class that reports the elapsed time diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md index e600a7f4..91d89210 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/Execute.md @@ -27,7 +27,7 @@ With [**Global**](Global) set to **False**, the collection holds at most one mat [**IgnoreCase**](IgnoreCase), [**MultiLine**](MultiLine) and [**DotAll**](DotAll) change what counts as a match. > [!WARNING] -> With **Global** set to **True**, a match of no characters is returned twice when the search had to skip at least one character to reach it, so the collection holds one **Match** too many at each such position. A pattern that can match no characters is affected: `$`, `\b`, `^` with **MultiLine** set to **True**, and a lookahead or lookbehind on its own. VBScript's **RegExp** returns each such match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. +> With **Global** set to **True**, a match of no characters is returned twice when the search had to skip at least one character to reach it, so the collection holds one **Match** too many at each such position. It happens to a pattern that matches no characters at a position after the one where the search started: `$`, `\b`, `^` with **MultiLine** set to **True**, and a lookahead or lookbehind on its own. A pattern such as `x*`, which matches no characters at the position where the search starts, is not affected. VBScript's **RegExp** returns each such match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. The pattern in this example matches no characters, before each capital letter. `fooBarBaz` has two capitals, and the collection holds four matches. diff --git a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md index 77845a75..486f7d9d 100644 --- a/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md +++ b/docs/Reference/Contributed/tbRegExp/RegExp/IsValid.md @@ -26,7 +26,7 @@ Check **IsValid** before [**Execute**](Execute), [**Test**](Test), [**Replace**] Although nothing is raised, the compile error of an invalid pattern stays in the **Err** object after the call that compiled the pattern returns. A program that tests **Err** for other errors calls **Err.Clear** first. > [!NOTE] -> Two faults are not found when the pattern is compiled, so **IsValid** returns **True** for them: a quantifier whose lower count is above its upper count, such as `a{2,1}`, and a backreference to a group that the pattern does not have, such as `(a)\2`. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise error 3000 when they use the pattern, with the description that Windows gives that number, *The specified print monitor is unknown.* This is how version 1.4.0.0 behaves. +> Two faults are not found when the pattern is compiled, so **IsValid** returns **True** for them: a quantifier whose lower count is above its upper count, such as `a{2,1}`, and a backreference to a group that the pattern does not have, such as `(a)\2`. [**Execute**](Execute), [**Test**](Test), [**Replace**](Replace) and [**Split**](Split) then raise error 3000 when a search reaches the quantifier or the backreference, with the description that Windows gives that number, *The specified print monitor is unknown.* This is how version 1.4.0.0 behaves. ## Example diff --git a/docs/Reference/Contributed/tbRegExp/index.md b/docs/Reference/Contributed/tbRegExp/index.md index 6fd51c3a..bf9a50e8 100644 --- a/docs/Reference/Contributed/tbRegExp/index.md +++ b/docs/Reference/Contributed/tbRegExp/index.md @@ -1,6 +1,6 @@ --- title: tbRegExp Package -parent: Contributed Packages +parent: Experimental Packages has_toc: false exclude_from_docs: - StaticRegex @@ -20,7 +20,7 @@ The matching is done by the [vba-regex](https://github.com/sihlfall/vba-regex) e Beyond VBScript's object, **RegExp** has the [**DotAll**](RegExp/DotAll) and [**Flags**](RegExp/Flags) options, the [**Split**](RegExp/Split) method, and [**IsValid**](RegExp/IsValid), [**LastError**](RegExp/LastError) and [**LastErrorNumber**](RegExp/LastErrorNumber), which report an invalid pattern before it is used. [**Replace**](RegExp/Replace) reads a `$` in the replacement string differently from VBScript. > [!WARNING] -> With [**Global**](RegExp/Global) set to **True**, a match of no characters is reported twice when the search had to skip at least one character to reach it. A pattern that can match no characters is affected: `$`, `\b`, `^` with [**MultiLine**](RegExp/MultiLine), and a lookahead or lookbehind on its own. [**Execute**](RegExp/Execute) returns the match twice, [**Replace**](RegExp/Replace) makes its replacement twice and [**Split**](RegExp/Split) adds an extra empty string, and nothing is raised. VBScript's **RegExp** reports such a match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. +> With [**Global**](RegExp/Global) set to **True**, a match of no characters is reported twice when the search had to skip at least one character to reach it. It happens to a pattern that matches no characters at a position after the one where the search started: `$`, `\b`, `^` with [**MultiLine**](RegExp/MultiLine), and a lookahead or lookbehind on its own. A pattern such as `x*`, which matches no characters at the position where the search starts, is not affected. [**Execute**](RegExp/Execute) returns the match twice, [**Replace**](RegExp/Replace) makes its replacement twice and [**Split**](RegExp/Split) adds an extra empty string, and nothing is raised. VBScript's **RegExp** reports such a match once. A match of one or more characters is never repeated, and with **Global** set to **False** nothing is. This is how version 1.4.0.0 behaves. ## Pattern syntax diff --git a/docs/Reference/Experimental.md b/docs/Reference/Experimental.md index c327a359..d2168674 100644 --- a/docs/Reference/Experimental.md +++ b/docs/Reference/Experimental.md @@ -20,5 +20,6 @@ These packages are published through TWINSERV, as the [Contributed Packages](../ - [**TBMANLIB_ConsoleCore**](../Contributed/TBMANLIB_ConsoleCore/) -- a console library with colours, UTF-8 and a full-screen mode. Version 1.0.0.1 compiles, and it reads keys wrongly and has several helpers that give wrong results. - [**TBMANLIB_Diagnostic**](../Contributed/TBMANLIB_Diagnostic/) -- a diagnostic report of the computer and its processes, as text, JSON or HTML. Version 0.0.0.0 compiles, and its text report, its **Dictionary** class and several of its list and file helpers fail or give wrong results. - [**TBMANLIB_Xml**](../Contributed/TBMANLIB_Xml/) -- XML documents parsed, edited and written, in twinBASIC code. Version 1.0.0.0 compiles, and its parser misreads some common XML, such as self-closing elements and entities in text, and does not return for some malformed text. +- [**tbRegExp**](../Contributed/tbRegExp/) -- regular expressions, in place of VBScript's **RegExp** object. Version 1.4.0.0 compiles, and with **Global** set to **True** it reports a match of no characters twice when the search skipped characters to reach it, so **Execute**, **Replace** and **Split** give wrong results for patterns such as `$`, `\b` and a lookahead. - [**WinReg**](../Contributed/WinReg/) -- registry keys and values, read, written, deleted and enumerated. Version 0.0.0.0 does not compile in twinBASIC BETA 1005. - [**xCalendar**](../Contributed/xCalendar/) -- a calendar control, in place of the Calendar control of `MSCAL.OCX`. Version 1.0.7.0 compiles, and has defects, among them some that can stop a program from responding. diff --git a/docs/_book.yml b/docs/_book.yml index 0094470e..3d729479 100644 --- a/docs/_book.yml +++ b/docs/_book.yml @@ -572,13 +572,6 @@ parts: landing_is_target: true outline_closed: true - - title: tbRegExp Package - subtitle: Regular expressions, in place of VBScript's RegExp object - landing_page: /tB/Packages/Contributed/tbRegExp/ - page: /tB/Packages/Contributed/tbRegExp/ - landing_is_target: true - outline_closed: true - - title: tsJson Package subtitle: A JSON model with parsing, JSONPath queries, JSON Pointer, JSON Patch and JSON Schema validation landing_page: /tB/Packages/Contributed/tsJson/ @@ -676,6 +669,13 @@ parts: landing_is_target: true outline_closed: true + - title: tbRegExp Package + subtitle: Regular expressions, in place of VBScript's RegExp object + landing_page: /tB/Packages/Contributed/tbRegExp/ + page: /tB/Packages/Contributed/tbRegExp/ + landing_is_target: true + outline_closed: true + - title: WinReg Package subtitle: Registry keys and values, read, written, deleted and enumerated landing_page: /tB/Packages/Contributed/WinReg/ From 67d4954304fb50c525228565b6b8e3c3d37bd64e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Mon, 12 Oct 2026 23:53:51 +0200 Subject: [PATCH 17/17] WinReg: moved to 1.0.1.1, still not compiling on BETA 1005; its own RegKeyspace and enumRegSzType, and WARNINGs on ReadString, GetRegistryValueType and ConvertValueToString, found by running a copy with the four calls corrected --- WIP.ExamplesBuild.md | 5 +- WIP.md | 2 +- builder/page-baseline.json | 2 +- docs/Documentation/Tools-Samples.md | 2 +- .../WinReg/RegCls/ConvertValueToString.md | 13 ++-- .../Contributed/WinReg/RegCls/CreateKey.md | 2 +- .../Contributed/WinReg/RegCls/DeleteKey.md | 2 +- .../Contributed/WinReg/RegCls/DeleteKeyEx.md | 4 +- .../Contributed/WinReg/RegCls/DeleteValue.md | 2 +- .../Contributed/WinReg/RegCls/EnumValues.md | 2 +- .../WinReg/RegCls/GetRegistryValueType.md | 5 +- .../Contributed/WinReg/RegCls/KeyExists.md | 2 +- .../Contributed/WinReg/RegCls/ReadDWORD.md | 2 +- .../Contributed/WinReg/RegCls/ReadString.md | 16 ++++- .../Contributed/WinReg/RegCls/ValueExists.md | 2 +- .../Contributed/WinReg/RegCls/WriteDWORD.md | 2 +- .../Contributed/WinReg/RegCls/WriteString.md | 2 +- .../Contributed/WinReg/RegCls/index.md | 35 +++++++---- .../Contributed/WinReg/RegKeyspace.md | 53 ++++++++++++++++ .../Contributed/WinReg/enumRegSzType.md | 45 ++++++++++++++ docs/Reference/Contributed/WinReg/index.md | 18 ++++-- docs/Reference/Experimental.md | 2 +- indexer/snapshots/contributed/WinReg/api.json | 60 ++++++++++++++++++- .../contributed-WinReg/Settings | 6 +- 24 files changed, 240 insertions(+), 46 deletions(-) create mode 100644 docs/Reference/Contributed/WinReg/RegKeyspace.md create mode 100644 docs/Reference/Contributed/WinReg/enumRegSzType.md diff --git a/WIP.ExamplesBuild.md b/WIP.ExamplesBuild.md index d76af6ca..25ad6e1a 100644 --- a/WIP.ExamplesBuild.md +++ b/WIP.ExamplesBuild.md @@ -330,11 +330,12 @@ the repository's to commit: four of the nine ship no licence file, and WinReg em one project, VBA_JSON's `Dictionary` class hid the `Scripting.Dictionary` that WinReg's samples name. - **A project does not see the names a package's own references declare.** WinReg embeds - WinDevLib, and its samples' `HKEY_CURRENT_USER`, `REGTYPES` and `BOOL` were unresolved + WinDevLib, and its samples' `REGTYPES`, `BOOL` and `RegOpenKeyEx` (and, before 1.0.1.1, + `HKEY_CURRENT_USER`, which WinReg's own `RegKeyspace` now supplies) were unresolved until `contributed-WinReg` referenced WinDevLib (at the version WinReg embeds, 8.8.0.507) and the Scripting Runtime itself. The WinReg landing page tells the reader the same. - **An error inside an embedded package is the package's, and fails nothing** - (`splitPackageFaults`). BigNumberLib 0.0.0.0, WinReg 0.0.0.0 and ArrayListLib 1.4.0.134 do not compile on BETA + (`splitPackageFaults`). BigNumberLib 0.0.0.0, WinReg 1.0.1.1 and ArrayListLib 1.4.0.134 do not compile on BETA 1005: each passes a pointer to a `ByRef` structure parameter without `ByVal` (TB5001). The template-alone build finds those rows; the run prints them as a note naming the package rather than as a template FAIL, every other template row still fails, and the samples are diff --git a/WIP.md b/WIP.md index 013ed45d..515e3458 100644 --- a/WIP.md +++ b/WIP.md @@ -34,7 +34,7 @@ sibling. History goes nowhere: git keeps it. Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set. -Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, tbRegExp, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text, and tbRegExp, with **Global**, reports a match of no characters twice when the search skipped characters to reach it (a defect of the vba-regex engine it is made from, confirmed by a second agent). TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. +Twenty-six **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: ArrayListLib, FileProps, Fmt, Generics, OLEGuids, WinReg, TwinTimerLib, tbFileSysTools, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Dialog, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, TBMANLIB_Xml, tbProjPacker, tbRegExp, tsJson, tsPwGen, VBA_JSON and xCalendar complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. The two console packages carry a NOTE (owner, 2026-10-12) that the samples harness cannot yet capture a console, so their console claims follow the source. Generics (seven tuple classes) and xCalendar (one control) are each one page (owner, 2026-10-11 and 10-12), so `analyze` in audit mode lists their classes and members as undocumented. What xCalendar's page says it does at run time comes from `test/package-probes/xCalendar/`, which runs the control on a form in a built exe. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; Generics' `exclude_from_docs` names its test code, `HelloWorldModule`, which the page does not mention. VBComDlg's `exclude_from_docs` names `CommonDialogBase`, a module whose public procedures only its class calls. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modImpExp` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. What TBMANLIB_Dialog's pages say its dialogs do comes from `test/package-probes/TBMANLIB_Dialog/`, which operates them in a built exe on a private desktop; run it again when the package's version changes. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each one has a chapter in the book's Packages part. **ArrayListLib, BigNumberLib, TBMANLIB, TBMANLIB_Aes, TBMANLIB_ConsoleComponents, TBMANLIB_ConsoleCore, TBMANLIB_Diagnostic, TBMANLIB_Xml, tbRegExp, WinReg and xCalendar are listed under Experimental Packages** (`docs/Reference/Experimental.md`, owner 2026-10-12): ArrayListLib, BigNumberLib and WinReg do not compile on BETA 1005 (each documented from its source alone, its samples compile-only; WinReg's methods were also run in a copy of its source with its four failing calls passed `ByVal`, and ReadString, GetRegistryValueType and the first ConvertValueToString give wrong results there), xCalendar has defects that can hang a program, TBMANLIB crashes the compiler in a 64-bit build and has many members that fail or give wrong results, TBMANLIB_ConsoleComponents cannot take a cConsole of the published TBMANLIB_ConsoleCore (it embeds a private copy of it), TBMANLIB_ConsoleCore reads keys wrongly, TBMANLIB_Diagnostic cannot create its Dictionary or make a text report and misplaces List items, TBMANLIB_Aes runs other cipher modes than the ones named (its default CBC is ECB) and fails the NIST test vectors, and TBMANLIB_Xml's parser misreads self-closing elements and entities and does not return for some malformed text, and tbRegExp, with **Global**, reports a match of no characters twice when the search skipped characters to reach it (a defect of the vba-regex engine it is made from, confirmed by a second agent). TBMANLIB_Xml's `exclude_from_docs` names its test module, `mXmlTests`, which its landing page describes in a paragraph; tsPwGen's names its five test modules and its six internal modules, and tsJson's its test and internal modules likewise, which their landing pages describe in a paragraph each. See *Where things live* for how a package moves between the two lists. The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check. diff --git a/builder/page-baseline.json b/builder/page-baseline.json index cf187a43..3cfe7aa0 100644 --- a/builder/page-baseline.json +++ b/builder/page-baseline.json @@ -1,5 +1,5 @@ { "src": "docs", - "pages": 1253, + "pages": 1255, "staticFiles": 1009 } diff --git a/docs/Documentation/Tools-Samples.md b/docs/Documentation/Tools-Samples.md index c54fea1d..69f2b057 100644 --- a/docs/Documentation/Tools-Samples.md +++ b/docs/Documentation/Tools-Samples.md @@ -56,7 +56,7 @@ Each marked sample is generated into its own `Module tbx_`, packed with a - `console` is the default. - `packages` references every package the IDE ships. A page under `Reference/Built-In/` or a package tutorial gets it without asking. - `form` is `console` with a real, empty `Form1`, for the samples that draw on a form or read its properties: a form made in code has no designer file and cannot be drawn on. -- `contributed-` is `console` with a reference to one contributed package, at the version its section's `indexed_from` names, and to what that package's samples name besides (WinReg's take WinDevLib's constants). A page under `Reference/Contributed//` gets it without asking, so each package's samples compile in a project that references that package alone, as a reader's does. The packages are not in the repository: the tool downloads each version from TWINSERV the first time it is needed, keeps it in `%TEMP%\tb-twinserv\`, and embeds it in every project built from the template. So the first run of these samples needs the network. An error inside an embedded package's own source fails nothing: the run reports it as a note naming the package, since the package is someone else's code, and the package's page says it does not compile. +- `contributed-` is `console` with a reference to one contributed package, at the version its section's `indexed_from` names, and to what that package's samples name besides (WinReg's need WinDevLib's types and declarations). A page under `Reference/Contributed//` gets it without asking, so each package's samples compile in a project that references that package alone, as a reader's does. The packages are not in the repository: the tool downloads each version from TWINSERV the first time it is needed, keeps it in `%TEMP%\tb-twinserv\`, and embeds it in every project built from the template. So the first run of these samples needs the network. An error inside an embedded package's own source fails nothing: the run reports it as a note naming the package, since the package is someone else's code, and the package's page says it does not compile. After each `check_run` sample the run unloads every form the sample left loaded, so a sample that forgets `Unload Form1` neither keeps the run waiting nor leaves its drawing for the next sample. diff --git a/docs/Reference/Contributed/WinReg/RegCls/ConvertValueToString.md b/docs/Reference/Contributed/WinReg/RegCls/ConvertValueToString.md index 19862062..47d55551 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/ConvertValueToString.md +++ b/docs/Reference/Contributed/WinReg/RegCls/ConvertValueToString.md @@ -28,6 +28,9 @@ Syntax: *object*.**ConvertValueToString**( *hKey*, *subkey*, *lType* ) Returns a **String**. For string types the null terminator is stripped. For DWORD types the value is returned as an eight-digit hexadecimal string prefixed with `0x`. For binary data the return value is formatted as `Binary (N bytes): XX XX ...` where each byte is a two-digit uppercase hex pair separated by spaces. For any other type code the return value is `Unsupported type: N`. +> [!WARNING] +> This overload does not find the value. It passes `StrPtr(subkey)` to a parameter that `RegQueryValueEx` declares `ByVal` **String**, so the name that reaches the function is not *subkey*, the query fails with error 2 (file not found), and the overload returns an empty string for `REG_SZ`, `REG_EXPAND_SZ`, the DWORD types and `REG_BINARY`. Only the `Unsupported type: N` result for any other type code is as described. Overload 2 and [**EnumValues**](EnumValues) are not affected. + ## Overload 2 -- convert from byte array Converts a byte array already read by `RegQueryValueEx` into a string representation. @@ -44,26 +47,26 @@ Returns a **String**. For string types the result is the text up to the first nu ### Remarks -The two overloads cover different calling patterns. Overload 1 is convenient when the value name and type are known up front and the caller wants a one-step result. Overload 2 is intended for batch or enumeration scenarios such as [**EnumValues**](EnumValues), where the raw bytes and the type code have already been read, and the caller passes both directly to avoid a second API call. +The two overloads cover different calling patterns. Overload 1 is meant for the case where the value name and type are known up front and the caller wants a one-step result. Overload 2 is intended for batch or enumeration scenarios such as [**EnumValues**](EnumValues), where the raw bytes and the type code have already been read, and the caller passes both directly to avoid a second API call. Overload 1 neither closes nor otherwise modifies *hKey*. When using Overload 1, open the key with at least `KEY_QUERY_VALUE` access and close it after all reads are complete. > [!NOTE] -> Both overloads include `On Error Resume Next`, so a run-time error inside them is not raised to the caller. Overload 1 returns an empty string when the query fails. If an empty string is returned unexpectedly, verify that *hKey* is valid, that the value named by *subkey* exists, and that *lType* matches the value's actual type. The source comments mark Overload 1 as not yet tested. +> Both overloads include `On Error Resume Next`, so a run-time error inside them is not raised to the caller. Overload 1 returns an empty string when the query fails. The source comments mark Overload 1 as not yet tested. ### Example -This example opens a registry key, reads a value using Overload 1, then closes the key. +This example opens a registry key, calls Overload 1 on a value, then closes the key. The key handle is a **LongPtr**, which the method takes as a **Long**. ```tb check_build Dim reg As New RegCls -Dim hKey As Long +Dim hKey As LongPtr Dim ret As Long Dim sData As String ret = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\MyApp", 0, KEY_READ, hKey) If ret = ERROR_SUCCESS Then - sData = reg.ConvertValueToString(hKey, "MyValue", REG_SZ) + sData = reg.ConvertValueToString(CLng(hKey), "MyValue", REG_SZ) Debug.Print sData RegCloseKey hKey End If diff --git a/docs/Reference/Contributed/WinReg/RegCls/CreateKey.md b/docs/Reference/Contributed/WinReg/RegCls/CreateKey.md index fc0cbc1d..2163082f 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/CreateKey.md +++ b/docs/Reference/Contributed/WinReg/RegCls/CreateKey.md @@ -12,7 +12,7 @@ Creates a registry key, including any intermediate keys in the path that do not Syntax: *object*.**CreateKey** ( *RootKey*, *KeyPath* ) *RootKey* -: *required* A **RegKeyspace** value identifying the root key under which the new key is created. Typical values are **HKEY_CURRENT_USER**, **HKEY_LOCAL_MACHINE**, and the other root constants of the **RegKeyspace** enumeration from **WinDevLib**. +: *required* A [**RegKeyspace**](../RegKeyspace) value identifying the root key under which the new key is created. Typical values are **HKEY_CURRENT_USER**, **HKEY_LOCAL_MACHINE**, and the other root constants of the **RegKeyspace** enumeration. *KeyPath* : *required* A **String** giving the subkey path relative to *RootKey*, using backslashes as separators --- for example, `"Software\MyApp\Settings\Advanced"`. All intermediate keys that do not yet exist are created. diff --git a/docs/Reference/Contributed/WinReg/RegCls/DeleteKey.md b/docs/Reference/Contributed/WinReg/RegCls/DeleteKey.md index 20cb344e..0270e9c7 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/DeleteKey.md +++ b/docs/Reference/Contributed/WinReg/RegCls/DeleteKey.md @@ -12,7 +12,7 @@ Deletes a registry key that has no subkeys. Syntax: *object*.**DeleteKey** ( *RootKey*, *KeyPath* ) *RootKey* -: *required* A **RegKeyspace** value identifying the root hive --- for example, `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) value identifying the root hive --- for example, `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** specifying the path of the key to delete, relative to *RootKey*. Segments are separated by backslashes --- for example, `"Software\MyApp"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/DeleteKeyEx.md b/docs/Reference/Contributed/WinReg/RegCls/DeleteKeyEx.md index 5972a84f..82bb470e 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/DeleteKeyEx.md +++ b/docs/Reference/Contributed/WinReg/RegCls/DeleteKeyEx.md @@ -12,7 +12,7 @@ Recursively deletes a registry key and all of its subkeys and values. Syntax: *object*.**DeleteKeyEx** ( *RootKey*, *KeyPath* ) *RootKey* -: *required* A **RegKeyspace** value identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) value identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** specifying the path of the key to delete, relative to *RootKey*. For example, `"Software\MyApp"`. @@ -21,7 +21,7 @@ Returns **True** if the key was deleted, **False** if the operation failed. ### Remarks -**DeleteKeyEx** opens the target key with `KEY_ENUMERATE_SUB_KEYS`, `KEY_QUERY_VALUE`, and `KEY_ALL_ACCESS` rights, then iterates through all subkeys using `RegEnumKeyEx`, calling itself recursively on each one. After all subkeys are deleted, it removes every value under the current key with `RegDeleteValue`, closes the handle, and removes the now-empty key with `RegDeleteKey`. +**DeleteKeyEx** opens the target key with `KEY_ENUMERATE_SUB_KEYS`, `KEY_QUERY_VALUE`, and `KEY_ALL_ACCESS` rights, then iterates through all subkeys using `RegEnumKeyEx`, calling itself recursively on each one. After all subkeys are deleted, it removes every value under the current key with `RegDeleteValue`, closes the handle, and removes the now-empty key with `RegDeleteKey`. The `KEY_ALL_ACCESS` that the class defines is `&H3F`, the six rights specific to a key, without the standard access rights that the Windows constant of the same name includes. This function is necessary because the Win32 `RegDeleteKey` API fails if the target key has subkeys. Use [**DeleteKey**](DeleteKey) instead when the key is known to have no subkeys. diff --git a/docs/Reference/Contributed/WinReg/RegCls/DeleteValue.md b/docs/Reference/Contributed/WinReg/RegCls/DeleteValue.md index 801f20a7..a99d1153 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/DeleteValue.md +++ b/docs/Reference/Contributed/WinReg/RegCls/DeleteValue.md @@ -12,7 +12,7 @@ Deletes a named value from a registry key and returns **True** if the deletion s Syntax: *object*.**DeleteValue**( **ByVal** *RootKey* **As RegKeyspace**, **ByVal** *KeyPath* **As String**, **ByVal** *ValueName* **As String** ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive to open. Typical values are **HKEY_CURRENT_USER** and **HKEY_LOCAL_MACHINE**. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive to open. Typical values are **HKEY_CURRENT_USER** and **HKEY_LOCAL_MACHINE**. *KeyPath* : *required* A **String** giving the path to the subkey that contains the value, relative to *RootKey*. Path components are separated by backslashes---for example, `"Software\MyApp"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/EnumValues.md b/docs/Reference/Contributed/WinReg/RegCls/EnumValues.md index e46f020d..25785230 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/EnumValues.md +++ b/docs/Reference/Contributed/WinReg/RegCls/EnumValues.md @@ -12,7 +12,7 @@ Returns a **Dictionary** containing the names and string representations of all Syntax: *object*.**EnumValues** ( *RootKey*, *KeyPath* ) *RootKey* -: *required* A **Long** identifying the root hive. Pass one of the `RegKeyspace` constants: **HKEY_CLASSES_ROOT**, **HKEY_CURRENT_USER**, **HKEY_LOCAL_MACHINE**, **HKEY_USERS**, etc. +: *required* A **Long** identifying the root hive. Pass one of the [**RegKeyspace**](../RegKeyspace) constants: **HKEY_CLASSES_ROOT**, **HKEY_CURRENT_USER**, **HKEY_LOCAL_MACHINE**, **HKEY_USERS**, etc. *KeyPath* : *required* A **String** giving the path to the subkey beneath *RootKey*, for example `"Software\MyApp"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/GetRegistryValueType.md b/docs/Reference/Contributed/WinReg/RegCls/GetRegistryValueType.md index fc657527..07493f9b 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/GetRegistryValueType.md +++ b/docs/Reference/Contributed/WinReg/RegCls/GetRegistryValueType.md @@ -12,7 +12,7 @@ Returns the data type of a named registry value without reading its data. Syntax: *object*.**GetRegistryValueType**( *hKey*, *subKey*, *valueName* ) **As REGTYPES** *hKey* -: *required* A **Long** holding a key handle, usually a predefined root key. Pass a `RegKeyspace` constant such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A **Long** holding a key handle, usually a predefined root key. Pass a [**RegKeyspace**](../RegKeyspace) constant such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *subKey* : *required* A **String** specifying the path to the registry key beneath *hKey*, for example `"Software\MyApp"`. @@ -24,6 +24,9 @@ Syntax: *object*.**GetRegistryValueType**( *hKey*, *subKey*, *valueName* ) **As If the key cannot be opened or the value query fails, the function returns `REGTYPES.REG_NONE`. +> [!WARNING] +> The function returns `REG_NONE` for every value that holds data. It asks `RegQueryValueEx` for the type with a data pointer and a size of zero, and the call fails with error 234 (*more data*) when the value has any data. Only a value of zero length, such as an empty `REG_BINARY`, gets its type. A program that needs the type of a value calls `RegQueryValueEx` itself. + > [!NOTE] > *hKey* is declared as **Long**, not as **RegKeyspace**. The two types are assignment-compatible in twinBASIC, so passing a `RegKeyspace` constant works without an explicit cast. diff --git a/docs/Reference/Contributed/WinReg/RegCls/KeyExists.md b/docs/Reference/Contributed/WinReg/RegCls/KeyExists.md index c242c3be..1af5bb78 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/KeyExists.md +++ b/docs/Reference/Contributed/WinReg/RegCls/KeyExists.md @@ -12,7 +12,7 @@ Returns **True** if the specified registry key exists, **False** otherwise. Syntax: *object*.**KeyExists**( *RootKey*, *KeyPath* ) **As Boolean** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** specifying the subkey path within *RootKey*, for example `"Software\MyApp"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/ReadDWORD.md b/docs/Reference/Contributed/WinReg/RegCls/ReadDWORD.md index 9cb89aea..748fdc9b 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/ReadDWORD.md +++ b/docs/Reference/Contributed/WinReg/RegCls/ReadDWORD.md @@ -12,7 +12,7 @@ Reads a **REG_DWORD** value from the Windows registry and returns it as a **Long Syntax: *object*.**ReadDWORD** ( *RootKey*, *KeyPath*, *ValueName* [ , *DefaultValue* ] ) *RootKey* -: *required* A **RegKeyspace** constant identifying the registry hive to read from, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the registry hive to read from, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** giving the path to the registry key, relative to *RootKey*. Components are separated by backslashes---for example, `"Software\MyApp\Settings"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/ReadString.md b/docs/Reference/Contributed/WinReg/RegCls/ReadString.md index fdcc89a1..cf00da4e 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/ReadString.md +++ b/docs/Reference/Contributed/WinReg/RegCls/ReadString.md @@ -12,7 +12,7 @@ Reads a **REG_SZ** string value from the Windows registry and returns it as a ** Syntax: *object*.**ReadString** ( *RootKey*, *KeyPath*, *ValueName* [, *DefaultValue* ] ) *RootKey* -: *required* A **RegKeyspace** value identifying the root hive to open. Common values are `HKEY_CURRENT_USER` and `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) value identifying the root hive to open. Common values are `HKEY_CURRENT_USER` and `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** giving the path to the registry key beneath *RootKey*, using backslashes as separators (for example, `"Software\MyApp"`). @@ -25,6 +25,9 @@ Syntax: *object*.**ReadString** ( *RootKey*, *KeyPath*, *ValueName* [, *DefaultV Returns a **String** containing the data stored in the registry value, or *DefaultValue* if the value cannot be read. +> [!WARNING] +> The string that **ReadString** returns is longer than the stored text. For a text of *n* characters the result has 2*n* + 1: the text, then *n* + 1 NUL characters (`Chr(0)`). The method cuts its buffer to the size that `RegQueryValueEx` reports, less one, and that size counts bytes while a character of the buffer is two bytes. `ReadString(...) = "Alice"` is therefore **False** for a stored `Alice`, and a stored empty string comes back as one NUL character. A *DefaultValue* is returned as it is, with no NUL characters. To get the text, cut the result at the first NUL, as the second example does. + ### Remarks **ReadString** opens the specified key with `KEY_QUERY_VALUE` access, queries the size and type of the named value, reads the data into a string buffer, then closes the key handle. The key handle is closed whether the read succeeds or fails, provided the key was opened successfully. @@ -45,6 +48,17 @@ UserName = Reg.ReadString(HKEY_CURRENT_USER, "Software\MyApp", "UserName", "Defa Debug.Print "User: " & UserName ``` +This example cuts the result at the first NUL character, which leaves the stored text, or the default: + +```tb check_build +Dim Reg As New RegCls +Dim UserName As String + +UserName = Reg.ReadString(HKEY_CURRENT_USER, "Software\MyApp", "UserName", "DefaultUser") +UserName = Split(UserName, vbNullChar)(0) +Debug.Print "User: " & UserName +``` + This example checks whether a value was present by comparing the result against the default: ```tb check_build diff --git a/docs/Reference/Contributed/WinReg/RegCls/ValueExists.md b/docs/Reference/Contributed/WinReg/RegCls/ValueExists.md index dadce091..429a0f9b 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/ValueExists.md +++ b/docs/Reference/Contributed/WinReg/RegCls/ValueExists.md @@ -12,7 +12,7 @@ Returns **True** if a named value exists under the specified registry key. Syntax: *object*.**ValueExists**( *RootKey*, *KeyPath*, *ValueName* ) *RootKey* -: *required* A **RegKeyspace** value identifying the root hive to search, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) value identifying the root hive to search, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** giving the path of the key beneath *RootKey*, using backslash as the separator---for example, `"Software\MyApp"`. diff --git a/docs/Reference/Contributed/WinReg/RegCls/WriteDWORD.md b/docs/Reference/Contributed/WinReg/RegCls/WriteDWORD.md index c041e549..c6788444 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/WriteDWORD.md +++ b/docs/Reference/Contributed/WinReg/RegCls/WriteDWORD.md @@ -12,7 +12,7 @@ Writes a 32-bit integer value (**REG_DWORD**) to a registry key, creating the ke Syntax: *object*.**WriteDWORD**(*RootKey*, *KeyPath*, *ValueName*, *ValueData*) *RootKey* -: *required* A **RegKeyspace** constant identifying the root key, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root key, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** giving the subkey path relative to *RootKey*, for example `"Software\MyApp\Settings"`. The key is created if it does not exist. diff --git a/docs/Reference/Contributed/WinReg/RegCls/WriteString.md b/docs/Reference/Contributed/WinReg/RegCls/WriteString.md index dcee7862..b517d605 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/WriteString.md +++ b/docs/Reference/Contributed/WinReg/RegCls/WriteString.md @@ -12,7 +12,7 @@ Writes a string value to a registry key, creating the key if it does not exist. Syntax: *object*.**WriteString**( *RootKey*, *KeyPath*, *ValueName*, *ValueData* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** specifying the subkey path within *RootKey*, for example `"Software\MyApp"`. Intermediate keys are created automatically if they do not exist. diff --git a/docs/Reference/Contributed/WinReg/RegCls/index.md b/docs/Reference/Contributed/WinReg/RegCls/index.md index 5e86f248..13d26ef7 100644 --- a/docs/Reference/Contributed/WinReg/RegCls/index.md +++ b/docs/Reference/Contributed/WinReg/RegCls/index.md @@ -10,7 +10,7 @@ has_toc: false A Windows Registry helper class that reads, writes, deletes, and enumerates registry keys and values through the Win32 `advapi32` API. -**RegCls** wraps the most common registry operations---reading and writing string and DWORD values, creating and deleting keys, checking whether a key or value exists, and enumerating all values under a key---into a single class. It depends on the types and API declarations from the **WinDevLib** package (`RegKeyspace`, `REGTYPES`, `RegOpenKeyEx`, `RegCreateKeyEx`, and so on); the source contains commented-out copies of those declarations and recommends using the **WinDevLib** package instead. +**RegCls** wraps the most common registry operations---reading and writing string and DWORD values, creating and deleting keys, checking whether a key or value exists, and enumerating all values under a key---into a single class. It declares the [**RegKeyspace**](../RegKeyspace) and [**enumRegSzType**](../enumRegSzType) enumerations and its own copies of the `advapi32` declarations it uses, and takes `RegOpenKeyEx`, `RegSetValueEx` and the types **BOOL** and **REGTYPES** from the **WinDevLib** package. A comment in the source recommends the declarations of **WinDevLib** over the class's own. ```tb check_build Dim reg As New RegCls @@ -55,6 +55,9 @@ Returns an empty string when the call fails. For `REG_SZ` / `REG_EXPAND_SZ` valu > [!NOTE] > This overload queries the value through the provided key handle. The caller must keep the handle open for the duration of the call and close it with `RegCloseKey` afterwards. The source comments mark this overload as not yet tested. +> [!WARNING] +> This overload does not find the value. It passes `StrPtr(subkey)` to a parameter that `RegQueryValueEx` declares `ByVal` **String**, so the name that reaches the function is not *subkey*, the query fails with error 2 (file not found), and the overload returns an empty string for `REG_SZ`, `REG_EXPAND_SZ`, the DWORD types and `REG_BINARY`. Any other type code returns `"Unsupported type: "` followed by the code. Overload 2 and [**EnumValues**](#enumvalues) are not affected. + ### ConvertValueToString (overload 2) {: .no_toc } @@ -78,7 +81,7 @@ Creates a registry key, including any intermediate sub-keys that do not yet exis Syntax: *object*.**CreateKey** ( *RootKey*, *KeyPath* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive, such as `HKEY_CURRENT_USER` or `HKEY_LOCAL_MACHINE`. *KeyPath* : *required* A **String** with the backslash-delimited sub-key path beneath *RootKey*, e.g. `"Software\MyApp\Settings\Advanced"`. Multi-level paths are created in one call. @@ -96,7 +99,7 @@ Deletes a registry key. The key must have no sub-keys for this call to succeed; Syntax: *object*.**DeleteKey** ( *RootKey*, *KeyPath* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path to delete beneath *RootKey*. @@ -111,7 +114,7 @@ Recursively deletes a registry key together with all its sub-keys and values. Syntax: *object*.**DeleteKeyEx** ( *RootKey*, *KeyPath* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path to delete beneath *RootKey*. @@ -129,7 +132,7 @@ Deletes a single named value from a registry key. Syntax: *object*.**DeleteValue** ( *RootKey*, *KeyPath*, *ValueName* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path containing the value. @@ -147,7 +150,7 @@ Returns all named values under a registry key as a **Dictionary** mapping each v Syntax: *object*.**EnumValues** ( *RootKey*, *KeyPath* ) **As Dictionary** *RootKey* -: *required* A **Long** identifying the root hive (compatible with the `RegKeyspace` enum values). +: *required* A **Long** identifying the root hive. Pass a member of [**RegKeyspace**](../RegKeyspace). *KeyPath* : *required* A **String** with the sub-key path to enumerate. @@ -174,6 +177,9 @@ Syntax: *object*.**GetRegistryValueType** ( *hKey*, *subKey*, *valueName* ) **As Returns a member of the `REGTYPES` enumeration (from **WinDevLib**), such as `REG_SZ`, `REG_DWORD`, or `REG_BINARY`. Returns `REG_NONE` if the sub-key cannot be opened or the value does not exist. +> [!WARNING] +> The method returns `REG_NONE` for every value that holds data. It asks `RegQueryValueEx` for the type with a data pointer and a size of zero, and the call fails with error 234 (*more data*) when the value has any data. Only a value of zero length, such as an empty `REG_BINARY`, gets its type. + ### KeyExists {: .no_toc } @@ -182,7 +188,7 @@ Returns whether a registry key exists. Syntax: *object*.**KeyExists** ( *RootKey*, *KeyPath* ) **As Boolean** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path to test. @@ -197,7 +203,7 @@ Reads a `REG_DWORD` value from the registry and returns it as a **Long**. Syntax: *object*.**ReadDWORD** ( *RootKey*, *KeyPath*, *ValueName* [, *DefaultValue* ] ) **As Long** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path containing the value. @@ -216,7 +222,7 @@ Reads a `REG_SZ` value from the registry and returns it as a **String**. Syntax: *object*.**ReadString** ( *RootKey*, *KeyPath*, *ValueName* [, *DefaultValue* ] ) **As String** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path containing the value. @@ -227,6 +233,9 @@ Syntax: *object*.**ReadString** ( *RootKey*, *KeyPath*, *ValueName* [, *DefaultV *DefaultValue* : *optional* A **String** returned when the key or value does not exist, or when the stored type is not `REG_SZ`. Default: `""` (empty string). +> [!WARNING] +> The string that **ReadString** returns is longer than the stored text. For a text of *n* characters the result has 2*n* + 1: the text, then *n* + 1 NUL characters (`Chr(0)`). The method cuts its buffer to the size that `RegQueryValueEx` reports, less one, and that size counts bytes while a character of the buffer is two bytes. `ReadString(...) = "Alice"` is therefore **False** for a stored `Alice`. A *DefaultValue* is returned as it is, with no NUL characters. To get the text, cut the result at the first NUL: `Split(ReadString(...), vbNullChar)(0)`. + ### ValueExists {: .no_toc } @@ -235,7 +244,7 @@ Returns whether a named value exists within a registry key. Syntax: *object*.**ValueExists** ( *RootKey*, *KeyPath*, *ValueName* ) **As Boolean** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path containing the value. @@ -253,7 +262,7 @@ Creates or updates a `REG_DWORD` value in the registry. Syntax: *object*.**WriteDWORD** ( *RootKey*, *KeyPath*, *ValueName*, *ValueData* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path. The key is created if it does not exist. @@ -274,7 +283,7 @@ Creates or updates a `REG_SZ` value in the registry. Syntax: *object*.**WriteString** ( *RootKey*, *KeyPath*, *ValueName*, *ValueData* ) **As BOOL** *RootKey* -: *required* A **RegKeyspace** constant identifying the root hive. +: *required* A [**RegKeyspace**](../RegKeyspace) constant identifying the root hive. *KeyPath* : *required* A **String** with the sub-key path. The key is created if it does not exist. @@ -292,7 +301,7 @@ Returns **True** on success, **False** if the key could not be created or the va ## Remarks -**RegCls** requires the **WinDevLib** package. The source file includes commented-out copies of the needed API declarations and enum constants as a reference, but the live code relies on WinDevLib's exported symbols (`RegOpenKeyEx`, `RegCreateKeyEx`, `RegSetValueEx`, `RegQueryValueEx`, `RegDeleteValue`, `RegDeleteKey`, `RegCloseKey`, `RegEnumKeyEx`, `RegEnumValue`, `RegKeyspace`, `REGTYPES`, and the `KEY_*` / `REG_*` / `ERROR_SUCCESS` constants). Add a reference to WinDevLib before compiling. +**RegCls** requires the **WinDevLib** package. The class declares the enumerations [**RegKeyspace**](../RegKeyspace) and [**enumRegSzType**](../enumRegSzType), its own copies of `RegCreateKeyEx`, `RegQueryValueEx`, `RegDeleteValue`, `RegDeleteKey`, `RegCloseKey`, `RegEnumKeyEx` and `RegEnumValue`, and the constants `ERROR_SUCCESS` and `KEY_*` that it uses. The code relies on **WinDevLib** for `RegOpenKeyEx`, `RegSetValueEx`, the types `REGTYPES` and `BOOL`, and the types that its own declarations use (`RegOptions`, `REGSAM`, `SECURITY_ATTRIBUTES`, `FILETIME` and `RegistryCreateDispositions`). The package embeds **WinDevLib**; a project that names those types or calls those functions itself references **WinDevLib** as well. The `BOOL` return type used by the create, write and delete methods is declared by WinDevLib. The methods assign it a **Boolean** result, so it can be tested directly in an `If` statement. diff --git a/docs/Reference/Contributed/WinReg/RegKeyspace.md b/docs/Reference/Contributed/WinReg/RegKeyspace.md new file mode 100644 index 00000000..5324f519 --- /dev/null +++ b/docs/Reference/Contributed/WinReg/RegKeyspace.md @@ -0,0 +1,53 @@ +--- +title: RegKeyspace +parent: WinReg Package +permalink: /tB/Packages/Contributed/WinReg/RegKeyspace +has_toc: false +--- + +# RegKeyspace enumeration +{: .no_toc } + +Names the predefined root keys of the registry. + +**RegKeyspace** is the type of the *RootKey* parameter of [**ReadString**](RegCls/ReadString), [**ReadDWORD**](RegCls/ReadDWORD), [**WriteString**](RegCls/WriteString), [**WriteDWORD**](RegCls/WriteDWORD), [**DeleteValue**](RegCls/DeleteValue), [**DeleteKey**](RegCls/DeleteKey), [**DeleteKeyEx**](RegCls/DeleteKeyEx), [**KeyExists**](RegCls/KeyExists), [**ValueExists**](RegCls/ValueExists) and [**CreateKey**](RegCls/CreateKey). [**EnumValues**](RegCls/EnumValues) and [**GetRegistryValueType**](RegCls/GetRegistryValueType) declare the same argument as a **Long** and take the same constants. + +The enumeration is declared inside the [**RegCls**](RegCls/) class, and its members are written without the class: `RegKeyspace.HKEY_CURRENT_USER`, or `HKEY_CURRENT_USER` alone. The form `RegCls.RegKeyspace.HKEY_CURRENT_USER` is refused (TB5027). + +| Constant | Value | Description | +|----------|-------|-------------| +| **HKEY_CLASSES_ROOT**{: #HKEY_CLASSES_ROOT } | `&H80000000` | File-type associations and COM class registrations. | +| **HKEY_CURRENT_USER**{: #HKEY_CURRENT_USER } | `&H80000001` | The settings of the user who runs the program. | +| **HKEY_LOCAL_MACHINE**{: #HKEY_LOCAL_MACHINE } | `&H80000002` | The settings of the computer. Writing under it typically requires administrator rights. | +| **HKEY_USERS**{: #HKEY_USERS } | `&H80000003` | The profiles of the users loaded on the computer. | +| **HKEY_PERFORMANCE_DATA**{: #HKEY_PERFORMANCE_DATA } | `&H80000004` | The performance data of the system, which Windows serves through the registry functions. | +| **HKEY_PERFORMANCE_TEXT**{: #HKEY_PERFORMANCE_TEXT } | `&H80000050` | The names and explanations of the performance counters. | +| **HKEY_PERFORMANCE_NLSTEXT**{: #HKEY_PERFORMANCE_NLSTEXT } | `&H80000060` | The national-language variant of **HKEY_PERFORMANCE_TEXT**. | +| **HKEY_CURRENT_CONFIG**{: #HKEY_CURRENT_CONFIG } | `&H80000005` | The hardware profile that the computer uses. | +| **HKEY_DYN_DATA**{: #HKEY_DYN_DATA } | `&H80000006` | Dynamic data of Windows 95, 98 and Me. Later versions of Windows do not have this key. | +| **HKEY_CURRENT_USER_LOCAL_SETTINGS**{: #HKEY_CURRENT_USER_LOCAL_SETTINGS } | `&H80000007` | The local settings of the current user. | + +The high bit of every value is set, so each value is a negative **Long**: `CLng(RegKeyspace.HKEY_CURRENT_USER)` is -2147483647. + +```tb check_build +Debug.Print Hex$(RegKeyspace.HKEY_CLASSES_ROOT) ' 80000000 +Debug.Print Hex$(RegKeyspace.HKEY_CURRENT_USER) ' 80000001 +Debug.Print CLng(RegKeyspace.HKEY_CURRENT_USER) ' -2147483647 +``` + +The **WinDevLib** package declares an enumeration of the same name with the same members and values. A project that references both **WinReg** and **WinDevLib** has two enumerations named **RegKeyspace**, and `WinReg.RegKeyspace` names this one. A member of either is accepted as an argument of a **RegCls** method. + +```tb check_build +Dim reg As New RegCls +Dim root As WinReg.RegKeyspace + +root = WinReg.RegKeyspace.HKEY_CURRENT_USER +Debug.Print reg.KeyExists(root, "Software\Microsoft") +Debug.Print reg.KeyExists(WinDevLib.RegKeyspace.HKEY_LOCAL_MACHINE, "SOFTWARE") +``` + +## See Also + +- [RegCls](RegCls/) class -- the methods that take a root key +- [enumRegSzType](enumRegSzType) enumeration -- the codes of the value types +- [WinReg package](./) -- overview diff --git a/docs/Reference/Contributed/WinReg/enumRegSzType.md b/docs/Reference/Contributed/WinReg/enumRegSzType.md new file mode 100644 index 00000000..3f92a5bb --- /dev/null +++ b/docs/Reference/Contributed/WinReg/enumRegSzType.md @@ -0,0 +1,45 @@ +--- +title: enumRegSzType +parent: WinReg Package +permalink: /tB/Packages/Contributed/WinReg/enumRegSzType +has_toc: false +--- + +# enumRegSzType enumeration +{: .no_toc } + +Names the type codes that the registry stores with a value to say what its data is. + +No parameter, property or return value of [**RegCls**](RegCls/) has the type **enumRegSzType**. [**GetRegistryValueType**](RegCls/GetRegistryValueType) returns the **REGTYPES** enumeration of **WinDevLib**, which has the same codes, adds `REG_QWORD` (11), and spells the ninth member `REG_FULL_RESOURCE_DESCRIPTOR`. + +The enumeration is declared inside the **RegCls** class, and its members are written without the class: `enumRegSzType.REG_SZ`, or `REG_SZ` alone. The form `RegCls.enumRegSzType.REG_SZ` is refused (TB5027). A project that references **WinDevLib** as well also has **REGTYPES**, with members of the same names. + +| Constant | Value | Description | +|----------|-------|-------------| +| **REG_SZ**{: #REG_SZ } | 1 | A string that ends with a null character. [**ReadString**](RegCls/ReadString) reads this type only. | +| **REG_EXPAND_SZ**{: #REG_EXPAND_SZ } | 2 | A string that ends with a null character and can contain unexpanded references to environment variables, such as `%PATH%`. | +| **REG_BINARY**{: #REG_BINARY } | 3 | Binary data of any form. | +| **REG_DWORD**{: #REG_DWORD } | 4 | A 32-bit number. [**ReadDWORD**](RegCls/ReadDWORD) reads this type only. | +| **REG_NONE**{: #REG_NONE } | 0 | No type. | +| **REG_DWORD_LITTLE_ENDIAN**{: #REG_DWORD_LITTLE_ENDIAN } | 4 | A 32-bit number with the least significant byte first. The same code as **REG_DWORD**. | +| **REG_DWORD_BIG_ENDIAN**{: #REG_DWORD_BIG_ENDIAN } | 5 | A 32-bit number with the most significant byte first. | +| **REG_LINK**{: #REG_LINK } | 6 | A Unicode string that names a symbolic link. | +| **REG_MULTI_SZ**{: #REG_MULTI_SZ } | 7 | A sequence of strings that each end with a null character, closed by an empty string. | +| **REG_RESOURCE_LIST**{: #REG_RESOURCE_LIST } | 8 | A list of the hardware resources of a device driver. | +| **REG_FULL_RESOURCE_DEscription**{: #REG_FULL_RESOURCE_DEscription } | 9 | A full description of the hardware resources of a device. The member is spelled `REG_FULL_RESOURCE_DEscription` in the package. | +| **REG_RESOURCE_REQUIREMENTS_LIST**{: #REG_RESOURCE_REQUIREMENTS_LIST } | 10 | A list of the hardware resources that a device driver requires. | + +[**EnumValues**](RegCls/EnumValues) converts the data of **REG_SZ**, **REG_EXPAND_SZ**, **REG_DWORD**, **REG_DWORD_LITTLE_ENDIAN**, **REG_DWORD_BIG_ENDIAN** and **REG_BINARY** values to text, and gives `"Unsupported type: "` and the code for every other type. + +```tb check_build +Debug.Print enumRegSzType.REG_SZ ' 1 +Debug.Print enumRegSzType.REG_DWORD ' 4 +Debug.Print enumRegSzType.REG_MULTI_SZ ' 7 +``` + +## See Also + +- [RegKeyspace](RegKeyspace) enumeration -- the root keys +- [GetRegistryValueType](RegCls/GetRegistryValueType) method -- the type code of a value +- [EnumValues](RegCls/EnumValues) method -- the values of a key as text +- [WinReg package](./) -- overview diff --git a/docs/Reference/Contributed/WinReg/index.md b/docs/Reference/Contributed/WinReg/index.md index bb78c734..c07326ef 100644 --- a/docs/Reference/Contributed/WinReg/index.md +++ b/docs/Reference/Contributed/WinReg/index.md @@ -2,21 +2,24 @@ title: WinReg Package parent: Experimental Packages has_toc: false -indexed_from: 0.0.0.0 +indexed_from: 1.0.1.1 permalink: /tB/Packages/Contributed/WinReg/ --- # WinReg Package {: .no_toc } -**Author:** forliny. **Version:** 0.0.0.0. **On GitHub:** [forliny/TbWinReg](https://github.com/forliny/TbWinReg) +**Author:** forliny. **Version:** 1.0.1.1. **On GitHub:** [forliny/TbWinReg](https://github.com/forliny/TbWinReg) -The **WinReg** contributed package provides a Windows Registry helper class that reads, writes, deletes, and enumerates registry keys and values through the Win32 `advapi32` API. The package exposes a single **RegCls** class wrapping the most common registry operations into a convenient interface. It depends on types and API declarations from the **WinDevLib** package. +The **WinReg** contributed package provides a Windows Registry helper class that reads, writes, deletes, and enumerates registry keys and values through the Win32 `advapi32` API. The package exposes a single **RegCls** class wrapping the most common registry operations into a convenient interface. It declares the [**RegKeyspace**](RegKeyspace) and [**enumRegSzType**](enumRegSzType) enumerations and its own copies of the `advapi32` declarations it uses, and takes the rest, among them `RegOpenKeyEx`, `RegSetValueEx` and the types **BOOL** and **REGTYPES**, from the **WinDevLib** package. A comment in the source recommends the declarations of **WinDevLib** over the package's own. -**WinReg** references the **WinDevLib** package, but a project does not see the names a package's own references declare. A project that names WinDevLib's root keys (`HKEY_CURRENT_USER`), value types (`REGTYPES`) or `BOOL`, as the examples here do, references **WinDevLib** as well. One that declares the **Dictionary** that [**EnumValues**](RegCls/EnumValues) returns references the Microsoft Scripting Runtime. +The root keys, such as `HKEY_CURRENT_USER`, are members of **RegKeyspace**, so a project names them with **WinReg** alone. **WinReg** references the **WinDevLib** package, but a project does not see the names a package's own references declare. A project that names `BOOL` or `REGTYPES`, or calls `RegOpenKeyEx` or `RegCloseKey` and uses the `KEY_*` constants, as some examples here do, references **WinDevLib** as well. One that declares the **Dictionary** that [**EnumValues**](RegCls/EnumValues) returns references the Microsoft Scripting Runtime. > [!NOTE] -> Version 0.0.0.0 does not compile in twinBASIC BETA 1005, so a project that references it does not build. **RegCls** passes `VarPtr(0&)` to two `ByRef` structure parameters of WinDevLib's declarations: *lpSecurityAttributes* of `RegCreateKeyEx` and *lpftLastWriteTime* of `RegEnumKeyEx`. A pointer passed for a structure has to be passed `ByVal` (error TB5001). +> Version 1.0.1.1 does not compile in twinBASIC BETA 1005, so a project that references it does not build. **RegCls** declares `RegCreateKeyEx` and `RegEnumKeyEx` with a `ByRef` structure parameter, *lpSecurityAttributes* (`SECURITY_ATTRIBUTES`) and *lpftLastWriteTime* (`FILETIME`), and passes `VarPtr(0&)` for it in [**WriteString**](RegCls/WriteString), [**WriteDWORD**](RegCls/WriteDWORD), [**CreateKey**](RegCls/CreateKey) and [**DeleteKeyEx**](RegCls/DeleteKeyEx). A pointer passed for a structure has to be passed `ByVal` (error TB5001). `VarPtr(0&)` is also the address of a temporary **Long**, not a null pointer; `ByVal vbNullPtr` passes a null pointer. The behaviour described on these pages is that of the package with those four calls passed `ByVal`. + +> [!WARNING] +> Three methods give wrong results. [**ReadString**](RegCls/ReadString) returns the text followed by NUL characters. [**GetRegistryValueType**](RegCls/GetRegistryValueType) returns **REG_NONE** for every value that holds data. The first overload of [**ConvertValueToString**](RegCls/ConvertValueToString) returns an empty string for the types it supports. ## Classes @@ -34,3 +37,8 @@ The **WinReg** contributed package provides a Windows Registry helper class that - [ValueExists](RegCls/ValueExists) -- returns True if a named value exists under the specified registry key - [WriteDWORD](RegCls/WriteDWORD) -- writes a 32-bit integer value (REG_DWORD) to a registry key, creating the key if it does not already exist - [WriteString](RegCls/WriteString) -- writes a string value to a registry key, creating the key if it does not exist + +## Enumerations + +- [enumRegSzType](enumRegSzType) -- the codes of the registry value types +- [RegKeyspace](RegKeyspace) -- the predefined root keys of the registry diff --git a/docs/Reference/Experimental.md b/docs/Reference/Experimental.md index d2168674..9048aa94 100644 --- a/docs/Reference/Experimental.md +++ b/docs/Reference/Experimental.md @@ -21,5 +21,5 @@ These packages are published through TWINSERV, as the [Contributed Packages](../ - [**TBMANLIB_Diagnostic**](../Contributed/TBMANLIB_Diagnostic/) -- a diagnostic report of the computer and its processes, as text, JSON or HTML. Version 0.0.0.0 compiles, and its text report, its **Dictionary** class and several of its list and file helpers fail or give wrong results. - [**TBMANLIB_Xml**](../Contributed/TBMANLIB_Xml/) -- XML documents parsed, edited and written, in twinBASIC code. Version 1.0.0.0 compiles, and its parser misreads some common XML, such as self-closing elements and entities in text, and does not return for some malformed text. - [**tbRegExp**](../Contributed/tbRegExp/) -- regular expressions, in place of VBScript's **RegExp** object. Version 1.4.0.0 compiles, and with **Global** set to **True** it reports a match of no characters twice when the search skipped characters to reach it, so **Execute**, **Replace** and **Split** give wrong results for patterns such as `$`, `\b` and a lookahead. -- [**WinReg**](../Contributed/WinReg/) -- registry keys and values, read, written, deleted and enumerated. Version 0.0.0.0 does not compile in twinBASIC BETA 1005. +- [**WinReg**](../Contributed/WinReg/) -- registry keys and values, read, written, deleted and enumerated. Version 1.0.1.1 does not compile in twinBASIC BETA 1005, and three of its methods give wrong results: **ReadString** returns the text followed by NUL characters, **GetRegistryValueType** returns **REG_NONE** for a value that holds data, and one overload of **ConvertValueToString** finds no value. - [**xCalendar**](../Contributed/xCalendar/) -- a calendar control, in place of the Calendar control of `MSCAL.OCX`. Version 1.0.7.0 compiles, and has defects, among them some that can stop a program from responding. diff --git a/indexer/snapshots/contributed/WinReg/api.json b/indexer/snapshots/contributed/WinReg/api.json index a96db620..38047d60 100644 --- a/indexer/snapshots/contributed/WinReg/api.json +++ b/indexer/snapshots/contributed/WinReg/api.json @@ -2,7 +2,7 @@ "format": 3, "package": "WinReg", "project": "WinReg", - "version": "0.0.0.0", + "version": "1.0.1.1", "types": [ { "name": "RegCls", @@ -17,15 +17,73 @@ {"name":"DeleteKey","kind":"function","vis":"public","signature":"Public Function DeleteKey(ByVal RootKey As RegKeyspace, ByVal KeyPath As String) As BOOL","returnType":"BOOL"}, {"name":"DeleteKeyEx","kind":"function","vis":"public","signature":"Public Function DeleteKeyEx(ByVal RootKey As RegKeyspace, ByVal KeyPath As String) As BOOL","returnType":"BOOL"}, {"name":"DeleteValue","kind":"function","vis":"public","signature":"Public Function DeleteValue(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String) As BOOL","returnType":"BOOL"}, + {"name":"ERROR_SUCCESS","kind":"const","vis":"private","signature":"Private Const ERROR_SUCCESS = 0&"}, {"name":"EnumValues","kind":"function","vis":"public","signature":"Public Function EnumValues(ByVal RootKey As Long, ByVal KeyPath As String) As Dictionary","returnType":"Dictionary"}, {"name":"GetRegistryValueType","kind":"function","vis":"public","signature":"Function GetRegistryValueType(ByVal hKey As Long, ByVal subKey As String, ByVal valueName As String) As REGTYPES","returnType":"REGTYPES"}, + {"name":"KEY_ALL_ACCESS","kind":"const","vis":"private","signature":"Private Const KEY_ALL_ACCESS = &H3F"}, + {"name":"KEY_CREATE_SUB_KEY","kind":"const","vis":"private","signature":"Private Const KEY_CREATE_SUB_KEY = &H4"}, + {"name":"KEY_ENUMERATE_SUB_KEYS","kind":"const","vis":"private","signature":"Private Const KEY_ENUMERATE_SUB_KEYS = &H8"}, + {"name":"KEY_QUERY_VALUE","kind":"const","vis":"private","signature":"Private Const KEY_QUERY_VALUE = &H1"}, + {"name":"KEY_READ","kind":"const","vis":"private","signature":"Private Const KEY_READ = &H20019"}, + {"name":"KEY_SET_VALUE","kind":"const","vis":"private","signature":"Private Const KEY_SET_VALUE = &H2"}, + {"name":"KEY_WOW64_64KEY","kind":"const","vis":"private","signature":"Private Const KEY_WOW64_64KEY = &H100"}, {"name":"KeyExists","kind":"function","vis":"public","signature":"Public Function KeyExists(ByVal RootKey As RegKeyspace, ByVal KeyPath As String) As Boolean","returnType":"Boolean"}, {"name":"ReadDWORD","kind":"function","vis":"public","signature":"Public Function ReadDWORD(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String, Optional DefaultValue As Long = -1) As Long","returnType":"Long"}, {"name":"ReadString","kind":"function","vis":"public","signature":"Public Function ReadString(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String, Optional DefaultValue As String = \"\") As String","returnType":"String"}, + {"name":"RegCloseKey","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function RegCloseKey Lib \"advapi32\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr) As Long","returnType":"Long"}, + {"name":"RegCreateKeyEx","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegCreateKeyEx Lib \"advapi32\" Alias \"RegCreateKeyExW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal lpSubKey As String, ByVal Reserved As LongPtr, ByVal lpClass As String, ByVal dwOptions As RegOptions, ByVal samDesired As REGSAM, lpSecurityAttributes As SECURITY_ATTRIBUTES, phkResult As LongPtr, lpdwDisposition As RegistryCreateDispositions) As Long","returnType":"Long"}, + {"name":"RegDeleteKey","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegDeleteKey Lib \"advapi32\" Alias \"RegDeleteKeyW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal lpSubKey As String) As Long","returnType":"Long"}, + {"name":"RegDeleteValue","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegDeleteValue Lib \"advapi32\" Alias \"RegDeleteValueW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal lpValueName As String) As Long","returnType":"Long"}, + {"name":"RegEnumKeyEx","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegEnumKeyEx Lib \"advapi32\" Alias \"RegEnumKeyExW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal dwIndex As Long, ByVal lpName As String, lpcchName As Long, ByVal lpReserved As LongPtr, ByVal lpClass As String, lpcchClass As Long, lpftLastWriteTime As FILETIME) As Long","returnType":"Long"}, + {"name":"RegEnumValue","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegEnumValue Lib \"advapi32\" Alias \"RegEnumValueW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved As LongPtr, lpType As REGTYPES, lpData As Byte, lpcbData As Long) As Long","returnType":"Long"}, + {"name":"RegOpenKeyExW","kind":"function","vis":"private","declare":true,"signature":"Private Declare PtrSafe Function RegOpenKeyExW Lib \"advapi32\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal lpSubKey As LongPtr, ByVal ulOptions As RegOptions, ByVal samDesired As REGSAM, phkResult As LongPtr) As Long","returnType":"Long"}, + {"name":"RegQueryValueEx","kind":"function","vis":"private","declare":true,"signature":"Private DeclareWide PtrSafe Function RegQueryValueEx Lib \"advapi32\" Alias \"RegQueryValueExW\" ([TypeHint(RegKeyspace)] ByVal hKey As LongPtr, ByVal lpValueName As String, ByVal lpReserved As LongPtr, lpType As REGTYPES, lpData As Any, lpcbData As Long) As Long","returnType":"Long"}, {"name":"ValueExists","kind":"function","vis":"public","signature":"Public Function ValueExists(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String) As Boolean","returnType":"Boolean"}, {"name":"WriteDWORD","kind":"function","vis":"public","signature":"Public Function WriteDWORD(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String, ByVal ValueData As Long) As BOOL","returnType":"BOOL"}, {"name":"WriteString","kind":"function","vis":"public","signature":"Public Function WriteString(ByVal RootKey As RegKeyspace, ByVal KeyPath As String, ByVal ValueName As String, ByVal ValueData As String) As BOOL","returnType":"BOOL"} ] + }, + { + "name": "RegKeyspace", + "kind": "enum", + "in": "RegCls", + "vis": "public", + "file": "RegCls.twin", + "signature": "Public Enum RegKeyspace", + "values": [ + {"name":"HKEY_CLASSES_ROOT","value":"&H80000000"}, + {"name":"HKEY_CURRENT_USER","value":"&H80000001"}, + {"name":"HKEY_LOCAL_MACHINE","value":"&H80000002"}, + {"name":"HKEY_USERS","value":"&H80000003"}, + {"name":"HKEY_PERFORMANCE_DATA","value":"&H80000004"}, + {"name":"HKEY_PERFORMANCE_TEXT","value":"&H80000050"}, + {"name":"HKEY_PERFORMANCE_NLSTEXT","value":"&H80000060"}, + {"name":"HKEY_CURRENT_CONFIG","value":"&H80000005"}, + {"name":"HKEY_DYN_DATA","value":"&H80000006"}, + {"name":"HKEY_CURRENT_USER_LOCAL_SETTINGS","value":"&H80000007"} + ] + }, + { + "name": "enumRegSzType", + "kind": "enum", + "in": "RegCls", + "vis": "public", + "file": "RegCls.twin", + "signature": "Public Enum enumRegSzType", + "values": [ + {"name":"REG_SZ","value":"&H1"}, + {"name":"REG_EXPAND_SZ","value":"&H2"}, + {"name":"REG_BINARY","value":"&H3"}, + {"name":"REG_DWORD","value":"&H4"}, + {"name":"REG_NONE","value":"0&"}, + {"name":"REG_DWORD_LITTLE_ENDIAN","value":"4&"}, + {"name":"REG_DWORD_BIG_ENDIAN","value":"5&"}, + {"name":"REG_LINK","value":"6&"}, + {"name":"REG_MULTI_SZ","value":"7&"}, + {"name":"REG_RESOURCE_LIST","value":"8&"}, + {"name":"REG_FULL_RESOURCE_DEscription","value":"9&"}, + {"name":"REG_RESOURCE_REQUIREMENTS_LIST","value":"10&"} + ] } ], "aliases": [], diff --git a/test/example-projects/contributed-WinReg/Settings b/test/example-projects/contributed-WinReg/Settings index 65792556..5c3f0251 100644 --- a/test/example-projects/contributed-WinReg/Settings +++ b/test/example-projects/contributed-WinReg/Settings @@ -55,10 +55,10 @@ "path32": "/Packages/WinReg", "path64": "/Packages/WinReg", "symbolId": "WinReg", - "versionBuild": "0", - "versionMajor": "0", + "versionBuild": "1", + "versionMajor": "1", "versionMinor": "0", - "versionRevision": "0" + "versionRevision": "1" }, { "autoCtlExt": true,