diff --git a/WIP.md b/WIP.md index 4de49c0..754f786 100644 --- a/WIP.md +++ b/WIP.md @@ -4,7 +4,7 @@ Jekyll site (`just-the-docs` theme) deploying to `docs.twinbasic.com`. Source un ## Status -Initial reference documentation is **complete**. All seven packages have full reference coverage 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. +Initial reference documentation is **complete**. All eight packages have full reference coverage 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. | Package | Reference | Tutorials | |--------------------------------------|-----------|-----------| @@ -15,6 +15,7 @@ Initial reference documentation is **complete**. All seven packages have full re | Assert package | done | — | | CustomControls / CustomControlsPackage | done | — | | cefPackage (CEF) | done | done | +| WinEventLogLib | done | — | The rest of this file is the maintenance guide for adding new pages or updating existing ones — primary-source paths, page templates, cross-section linking conventions, the per-symbol workflow, and the integrity check. @@ -30,6 +31,7 @@ When working from a primary source: always read it first — **never paraphrase - `docs/Reference/WebView2/` — WebView2 package: the **WebView2** control class plus its small wrapper classes (request / response / headers / environment options) and the `wv2…` enumerations. - `docs/Reference/CustomControls/` — CustomControls package: the eight **Waynes…** custom controls, their shared `Styles/` helper classes (`Fill`, `Borders`, `Corners`, `TextRendering`, …), the `Framework/` DESIGNER surface (interfaces, CoClasses, the `Canvas` / `SerializeInfo` UDTs), and the `Enumerations/` (`CornerShape`, `FillPattern`, `DockMode`, …). - `docs/Reference/CEF/` — CEF (Chromium Embedded Framework) package: the **CefBrowser** control, its `EnvironmentOptions` sub-page, and the two user-facing enumerations (`CefLogSeverity`, `cefPrintOrientation`). This is a much smaller surface than WebView2 — the package is currently BETA and many WebView2-equivalent features are not yet exposed. +- `docs/Reference/WinEventLogLib/` — Windows Event Log package: the generic `EventLog(Of T1, T2)` class and the `EventLogHelperPublic` module with its single `RegisterEventLogInternal` helper. Three pages total — `index.md`, `EventLog.md`, `EventLogHelperPublic.md`. - `docs/Reference/Statements.md` — alphabetical index of language statements. - `docs/Reference/Procedures and Functions.md` — alphabetical index of procedures/functions. - `docs/_includes/footer_custom.html` — overrides the theme's footer slot; renders the copyright line and, when `vba_attribution: true` is set in a page's frontmatter, an additional CC-BY-4.0 attribution line beneath it. @@ -60,13 +62,14 @@ All of twinbasic's package sources are at: ..\tb-export\NewProject\Packages\Assert\Sources\ ..\tb-export\NewProject\Packages\CustomControls\Sources\ ..\tb-export\NewProject\Packages\CustomControlsPackage\Sources\ +..\tb-export\NewProject\Packages\cefPackages\Sources\ +..\tb-export\NewProject\Packages\WinEventLogLib\Sources\ etc. ``` -For the CEF package, the sources live in a separate sibling tree (not under `tb-export`): +For the CEF package, the examples live in a different folder: ``` -..\tbrepro\cef\CEFSampleProject\Packages\cefPackage\Sources\ ..\tbrepro\cef\CEFSampleProject\Sources\ ← four worked examples + MainForm ``` @@ -315,7 +318,7 @@ docs/Reference/CustomControls/ ### cefPackage (CEF) -Layout of `..\tbrepro\cef\CEFSampleProject\Packages\cefPackage\Sources\`: +Layout of `..\tb-export\NewProject\Packages\cefPackages\Sources\`: - `CefControl.twin` — contains three classes: the private `CefBrowserBaseCtl` (where every event / method / property is declared), the private `CefEnvironmentOptions` (a bare-field options class), and the public `CefBrowser` control which only inherits from `CefBrowserBaseCtl` and sets the design-time icon. This single file is the entire user-facing surface of the package. - `CefControlGlobalWnd.twin` — private internal message-window plumbing; no doc page. @@ -395,6 +398,59 @@ docs/Reference/CEF/ **License:** MIT (Wayne Phillips T/A iTech Masters) — same situation as WebView2Package, Assert, and CustomControls. The Settings file doesn't carry an explicit `licence:` field but every other package by this author is MIT and the wiki implies the same. Pages are fully original; **omit** the `vba_attribution: true` flag. +### WinEventLogLib + +Layout of `..\tb-export\NewProject\Packages\WinEventLogLib\Sources\` is flat — four `.twin` files plus three text files (`_README.txt`, `_LICENCE.txt`, `_RELEASE_HISTORY.txt`): + +- `APIs.twin` — `Private Module EventLogAPIs` wrapping six `advapi32.dll` entry points (`RegCreateKeyExW`, `RegSetValueExW`, `RegCloseKey`, `RegDeleteKeyExW`, `RegisterEventSourceW`, `ReportEventW`). No doc page. +- `Constants.twin` — `Private Module EventLogConstants` carrying `Public Enum EventLogTypeConstants` (`vbEventLogTypeSuccess`, `vbEventLogTypeAuditFailure`, `vbEventLogTypeAuditSuccess`, `vbEventLogTypeError`, `vbEventLogTypeWarning`). The module is `Private`, so the enum does not surface in the public API; no doc page. +- `EventLog.twin` — the generic `Public Class EventLog(Of T1, T2)`. The only user-facing class. +- `Helper.twin` — two modules: `Public Module EventLogHelperPrivate` (one helper `VariantArrayToStringArray`, used only by `EventLog.LogArray` internally — its name signals *intended* private but the module is declared `Public`; treat as internal and skip) and `Public Module EventLogHelperPublic` (one user-facing helper `RegisterEventLogInternal`). + +Public user-facing surface (one generic class + one helper module): + +| Symbol | Kind | Role | +|---------------------------------|---------------------|---------------------------------------------------------------------------------------| +| `EventLog(Of T1, T2)` | Generic class | Main user-facing class. `T1` is the event-ID enum, `T2` is the category enum. | +| `EventLogHelperPublic` | Public module | Holds the low-level `RegisterEventLogInternal` helper. | +| `RegisterEventLogInternal` | `Sub` on the module | Registry-write helper; `EventLog.Register()` is the normal entry point. | + +`EventLog(Of T1, T2)` public members: + +- `Public Sub New(LogName As String)` — constructor. `LogName` is either a leaf name (`"MyService"`, registered under `Application\MyService`) or a full path (`"System\MyService"`, registered under `System\MyService`). +- `Public Sub LogSuccess(ByVal EventId As T1, ByVal CategoryId As T2, ParamArray AdditionalStrings())` — writes an **Information**-type event (`EVENTLOG_SUCCESS = 0`). The name "Success" is the Win32 SDK constant's literal name, *not* the audit-success category — the underlying event type is **Information**. +- `Public Sub LogFailure(ByVal EventId As T1, ByVal CategoryId As T2, ParamArray AdditionalStrings())` — writes an **Error**-type event (`EVENTLOG_ERROR_TYPE = 1`). +- `Public Sub Register()` — writes the registry entries under `HKLM\SYSTEM\CurrentControlSet\Services\EventLog\…` to declare this EXE as the message provider for the source. Calls `RegisterEventLogInternal(LogName, GetDeclaredMaxEnumValue(Of T2))` — the category count is derived from `T2`'s declared maximum value at compile time. + +Class-level decoration on `EventLog`: `[COMCreatable(False)]`, `[ClassId("4AEA12E8-…-EAEAEAEAEAEA")]` (the `EA` suffix triggers special compiler handling for generic classes). The `[Description]` attribute on the class is the basis for the page intro: *"This is the main event log (generic) class."* + +`EventLogHelperPublic` public members: + +- `Public Sub RegisterEventLogInternal(ByVal LogPath As String, ByVal CategoryCount As Long)` — the registry-write helper. Prepends `"Application\"` to *LogPath* if no backslash is present, opens `HKLM\SYSTEM\CurrentControlSet\Services\EventLog\` with `KEY_WRITE`, then writes `EventMessageFile` and `CategoryMessageFile` (both set to `App.ModulePath`) and `CategoryCount`. Requires admin rights (registry writes to HKLM). Raises run-time error 5 with the message *"Failed to register event log source (\)"* if the open fails. Normally callers use `EventLog.Register()`, which fills *CategoryCount* automatically. + +**Gaps and quirks** to surface on the docs (drawn from a static read of the source): + +- The `EventLogTypeConstants` enum has five values (`Success`, `Warning`, `Error`, `AuditSuccess`, `AuditFailure`) but the public class only exposes Information and Error event types — Warning and Audit events are not currently reachable. +- Method names follow the Win32 SDK constants verbatim: `LogSuccess` writes an *Information* event (because `EVENTLOG_SUCCESS = 0` is the Win32 spelling for the information type), and `LogFailure` writes an *Error* event. Call this out on the per-method entries. +- Message resources: the registry entries point at `App.ModulePath` (the running EXE) for both `EventMessageFile` and `CategoryMessageFile`. Windows therefore expects a message-table resource keyed by the `T1` and `T2` enum values to be embedded in the EXE. The `.twin` source does not itself synthesise that resource — there is no `mc.exe` invocation or message-table emit visible in `WinEventLogLib\Sources\`; whatever mechanism populates the resource sits in the compiler's special-handling path for the `[ClassId("…EAEAEAEAEAEA")]` magic-byte pattern. The docs describe what Windows expects without making strong claims about how the compiler delivers it. +- `Register()` requires elevation. Normal usage is to call it once during install (from an elevated installer), then call `LogSuccess` / `LogFailure` at runtime without elevation. +- The package is described in `_README.txt` with a copy-pasted "NAMED PIPES PACKAGE" header (clearly an unintentional carry-over from another sister package); the body correctly says *"A simple framework for creating Windows event log entries from twinBASIC"*. Use the body, not the header. + +**Layout decision** — three pages total, mirroring the small-package approach used by Assert: + +- `docs/Reference/WinEventLogLib/index.md` — landing page: intro, lifecycle (define enums → instantiate → Register once → LogSuccess / LogFailure), gaps and quirks, the class and module lists. +- `docs/Reference/WinEventLogLib/EventLog.md` — the generic class, single-file (no sub-pages — the surface is small). +- `docs/Reference/WinEventLogLib/EventLogHelperPublic.md` — the helper module, single-file (one Sub listed under a `## RegisterEventLogInternal` heading, same shape as Assert per-member sections). + +**Naming:** + +- Folder / URL segment: `WinEventLogLib/` (matches the source-side package name; no `Package` suffix to drop, the package isn't named with that suffix in `Settings`). +- Index title: `WinEventLogLib Package` — the ` Package` convention used by every other package landing. +- Permalinks: `/tB/Packages/WinEventLogLib/` for the landing; `/tB/Packages/WinEventLogLib/EventLog` and `/tB/Packages/WinEventLogLib/EventLogHelperPublic` for the two member pages. +- `parent: WinEventLogLib Package` on each child page (matching the index `title:`, the same split every other package uses). + +**License:** MIT (copyright Wayne Phillips T/A iTech Masters, 2025; first release v0.1, 04-FEB-2025) — same situation as WebView2Package, Assert, CustomControls, and CEF. Pages are fully original content; **omit** the `vba_attribution: true` flag. + ## Page template Match the existing style. Worked examples to imitate: @@ -407,13 +463,14 @@ Match the existing style. Worked examples to imitate: - VB control class (folder-style): `docs/Reference/VB/CheckMark/index.md`. - Assert module page (single-file, all members inline): `docs/Reference/Assert/Exact.md`. - CEF control class (folder-style with a sub-page): `docs/Reference/CEF/CefBrowser/index.md` + `docs/Reference/CEF/CefBrowser/EnvironmentOptions.md`. +- Generic class (single-file, `(Of T1, T2)`): `docs/Reference/WinEventLogLib/EventLog.md`. Skeleton: ````markdown --- title: -parent: Module | VB Package> +parent: Module | Package> # Pick the permalink that matches the section: # Core → /tB/Core/ # VBA module → /tB/Modules// (legacy URL scheme retained) @@ -476,6 +533,8 @@ The URL prefixes are *not* uniform across packages — VBA pages live one segmen - CEF `CefBrowser` class → `/tB/Packages/CEF/CefBrowser/` (folder-style — has the `EnvironmentOptions` sub-page) - CEF `EnvironmentOptions` sub-page → `/tB/Packages/CEF/CefBrowser/EnvironmentOptions` - CEF enumeration → `/tB/Packages/CEF/Enumerations/` +- WinEventLogLib class → `/tB/Packages/WinEventLogLib/EventLog` (single-file; same depth as a single-file VB class) +- WinEventLogLib module → `/tB/Packages/WinEventLogLib/EventLogHelperPublic` (single-file; same depth as an Assert module) Common patterns: @@ -543,6 +602,9 @@ Common patterns: | CEF `Packages/CEF/Enumerations/X` | sibling `Enumerations/Y` | `[Y](Y)` | | CEF `Packages/CEF/Enumerations/X` | CEF `Packages/CEF/CefBrowser/` (folder-style) | `[Y](../CefBrowser/)` | | CEF `Packages/CEF/Enumerations/X` | CEF `Packages/CEF/CefBrowser/EnvironmentOptions` | `[Y](../CefBrowser/EnvironmentOptions)` | +| WinEventLogLib `Packages/WinEventLogLib/X` | sibling `Packages/WinEventLogLib/Y` | `[Y](Y)` | +| WinEventLogLib `Packages/WinEventLogLib/X` | VBA `Modules//Y` | `[Y](../../Modules//Y)` | +| WinEventLogLib `Packages/WinEventLogLib/X` | `Core/Y` | `[Y](../../Core/Y)` | | `Core/X` | VBA `Modules//Y` | `[Y](../Modules//Y)` | | `Core/X` | VBRUN `Packages/VBRUN//Y` | `[Y](../Packages/VBRUN//Y)` | | `Core/X` | VB `Packages/VB/Y` | `[Y](../Packages/VB/Y)` | @@ -550,6 +612,7 @@ Common patterns: | `Core/X` | Assert `Packages/Assert/` | `[Y](../Packages/Assert/)` | | `Core/X` | CC `Packages/CustomControls/Y` | `[Y](../Packages/CustomControls/Y)` | | `Core/X` | CEF `Packages/CEF/Y` | `[Y](../Packages/CEF/Y)` | +| `Core/X` | WinEventLogLib `Packages/WinEventLogLib/Y` | `[Y](../Packages/WinEventLogLib/Y)` | | `Core/X` | `Core/Y` (sibling) | `[Y](Y)` | Always link to the **canonical** location (the page's `permalink:`), not to a `redirect_from` alias. Pages that have moved out of `Core/` retain a `redirect_from: /tB/Core/` so legacy links still work, but forward-style links should point at the new home. @@ -563,6 +626,7 @@ Always link to the **canonical** location (the page's `permalink:`), not to a `r - Assert package → `..\tb-export\NewProject\Packages\Assert\Sources\.twin` (one file per module — `Exact.twin`, `Strict.twin`, `Permissive.twin`). - CustomControls — framework half: `..\tb-export\NewProject\Packages\CustomControls\Sources\CustomControls.twin` (a single file with `Module Constants`, the interfaces, and the CoClasses). Runtime half: `..\tb-export\NewProject\Packages\CustomControlsPackage\Sources\Waynes.twin` for each control + `zTemporarySupport.twin` for the shared style helpers and the mixin base classes. - CEF package → `..\tbrepro\cef\CEFSampleProject\Packages\cefPackage\Sources\CefControl.twin` for the whole public surface (the `CefBrowser` control, its `CefBrowserBaseCtl` base, and `CefEnvironmentOptions`). For the two surfaced enums: `CEF\Enums\_cef_log_severity_t.twin` (declares both the internal `cef_log_severity_t` and the user-facing `CefLogSeverity`) and `CEF\CrossProcessIPC\BrowserOM.twin` (declares `cefPrintOrientation` inline, around line 29). Everything else under `cefPackage\Sources\` and `cefPackage\Sources\CEF\` is `Private Class` / `Private Module` plumbing — skip. The sample project's `Sources\Example1..4.twin` are the source-of-truth for which features are *not* yet exposed (commented-out event handlers with *"Sorry, this feature is not yet available in the CEF package"*). + - WinEventLogLib package → `..\tb-export\NewProject\Packages\WinEventLogLib\Sources\EventLog.twin` (the generic `EventLog(Of T1, T2)` class) and `Helper.twin` (`EventLogHelperPublic.RegisterEventLogInternal`). Skip `APIs.twin` (`Private Module`), `Constants.twin` (`Private Module` — the `EventLogTypeConstants` enum is unreachable from outside the package), and the `EventLogHelperPrivate` module in `Helper.twin` (named "Private" though declared `Public`; only used internally by `EventLog.LogArray`). 2. **Decide placement**: - Pure language keyword (parsed by the compiler, no runtime call) → `docs/Reference/Core/`. - Runtime function/property → `docs/Reference///`. Add `redirect_from: /tB/Core/` so legacy `tB/Core/` links still work. @@ -576,6 +640,7 @@ Always link to the **canonical** location (the page's `permalink:`), not to a `r - CustomControls framework symbol (interface, CoClass, UDT) → `docs/Reference/CustomControls/Framework/.md`. - CustomControls enumeration → `docs/Reference/CustomControls/Enumerations/.md` (mirrors `WebView2/Enumerations/` and `VBRUN/Constants/`). The three `Long`-alias enums (`ColorRGBA`, `PixelCount`, `PointSize`) live here too, even though they're really typedefs. - CEF control → `docs/Reference/CEF/CefBrowser/index.md` (folder-style; carries the `EnvironmentOptions` sub-page). Pre-creation options class → `docs/Reference/CEF/CefBrowser/EnvironmentOptions.md` (parallel to `WebView2/WebView2/EnvironmentOptions.md`). CEF enumeration → `docs/Reference/CEF/Enumerations/.md`. + - WinEventLogLib generic class → `docs/Reference/WinEventLogLib/EventLog.md` (single-file; the surface is small — constructor + three methods). WinEventLogLib helper module → `docs/Reference/WinEventLogLib/EventLogHelperPublic.md` (single-file; one Sub). - Pick `` from VBA's grouping (Information, Interaction, Strings, FileSystem, DateTime, Math, Financial, Conversion, ...) and the existing folders under `Reference//`. 3. **Adapt content** (VBA-Docs sources): - Strip MS frontmatter (`ms.assetid`, `f1_keywords`, `keywords`, `ms.date`, `ms.localizationpriority`). @@ -623,10 +688,21 @@ Always link to the **canonical** location (the page's `permalink:`), not to a `r - WebView2-parity gap list lives on `CEF/index.md` (one bulleted section). Methods / events not yet exposed get **no per-page stub** — they don't exist on `CefBrowser` and have no place to land. - Multi-version source: the same `.twin` files compile for CEF v49 / v109 / v145 via the `CEF_VERSION` compiler constant. Mention this on `CEF/index.md` together with the runtime download story; reference `CefBrowser.CefMajorVersion` as the runtime-side query. - Omit the `vba_attribution: true` frontmatter flag — these pages are fully original (the package is MIT-licensed, same as WebView2 / Assert / CustomControls). -9. **Flag tB deviations** with a `> [!NOTE]` callout (see next section). -10. **Update the parent index** (`//index.md`, `docs/Reference/VB/index.md`, `docs/Reference/WebView2/index.md`, `docs/Reference/Assert/index.md`, `docs/Reference/CustomControls/index.md` (and its `Styles/`, `Framework/`, `Enumerations/` sub-indices), `docs/Reference/CEF/index.md` (and its `Enumerations/` sub-index), `Reference/Statements.md`, or `Reference/Procedures and Functions.md`) — turn an unlinked bullet into a link with a short blurb. Match the existing style of the page. If a new package is being added, also extend `docs/Reference/Packages.md` to list it. -11. **Add the page** to `Reference/Statements.md` or `Reference/Procedures and Functions.md` if it's a statement or callable and not already listed there. -12. **Run the [site integrity check](#site-integrity-check)** after the batch and before committing. +9. **Adapt content** (WinEventLogLib `.twin` sources): + - The generic class declaration `Public Class EventLog(Of T1, T2)` follows the same syntax described in `docs/Features/Language/Generics.md` (look there for the parameterisation rules). Show the constructor as `New EventLog(Of , )(LogName)` — both type arguments are required because twinBASIC does not deduce them from the `LogName` constructor argument. + - The `[Description("…")]` attributes on the class and on each `Public Sub` are the IDE one-liner — use them as the basis for each entry, then expand. + - The class itself is tagged `[COMCreatable(False)]` and `[ClassId("4AEA12E8-…-EAEAEAEAEAEA")]`. The `EA` byte sequence is *compiler magic* for generic classes — do not surface it on the page (it's an implementation detail of how generics are exposed to COM). + - Method-name quirk: `LogSuccess` writes a Windows *Information* event (`EVENTLOG_SUCCESS = 0` is the Win32 SDK spelling for the information event type). `LogFailure` writes a Windows *Error* event. Call this out on each method entry — readers familiar with the Windows Event Log will otherwise expect `LogSuccess` to write an Audit Success entry. + - `Register()` requires elevation (it writes to `HKLM`); typical usage is *"call once during install"*. Call this out on the method entry. + - For `EventLogHelperPublic.RegisterEventLogInternal`: do not surface the `Const HKEY_LOCAL_MACHINE` / `Const KEY_WRITE` declarations or the `RegCreateKeyExW` / `RegSetValueExW` Win32 calls — those are implementation detail. Describe what the function *does* at the registry (writes the source key with `EventMessageFile = App.ModulePath`, `CategoryMessageFile = App.ModulePath`, `CategoryCount = `). + - On the index page, mention the package's current gaps in passing: the `EventLogTypeConstants` enum has five entries (Information / Warning / Error / AuditSuccess / AuditFailure) but the public API surfaces only Information and Error event types — Warning and the two Audit variants are not yet reachable. + - The index page's *Message resources* section should describe what Windows *expects* (a message-table resource in the EXE pointed at by `EventMessageFile`, keyed by the `T1` / `T2` enum values), **not** make strong claims about how twinBASIC delivers it. The `.twin` source does not contain visible `mc.exe`-equivalent emit; whatever populates the resource lives in the compiler's special-handling path for the `[ClassId("…EAEAEAEAEAEA")]` magic-byte pattern, and that is not directly observable from the package's own sources. + - The README copy-paste mistake (header says "NAMED PIPES PACKAGE", body is correct) is *not* surfaced on the docs — write the actual description ("a simple framework for creating Windows event log entries"), don't propagate the wrong name. + - Omit the `vba_attribution: true` frontmatter flag — these pages are fully original (the package is MIT-licensed, same situation as the other Wayne Phillips packages). +10. **Flag tB deviations** with a `> [!NOTE]` callout (see next section). +11. **Update the parent index** (`//index.md`, `docs/Reference/VB/index.md`, `docs/Reference/WebView2/index.md`, `docs/Reference/Assert/index.md`, `docs/Reference/CustomControls/index.md` (and its `Styles/`, `Framework/`, `Enumerations/` sub-indices), `docs/Reference/CEF/index.md` (and its `Enumerations/` sub-index), `docs/Reference/WinEventLogLib/index.md`, `Reference/Statements.md`, or `Reference/Procedures and Functions.md`) — turn an unlinked bullet into a link with a short blurb. Match the existing style of the page. If a new package is being added, also extend `docs/Reference/Packages.md` to list it. +12. **Add the page** to `Reference/Statements.md` or `Reference/Procedures and Functions.md` if it's a statement or callable and not already listed there. +13. **Run the [site integrity check](#site-integrity-check)** after the batch and before committing. ## twinBASIC deviations from VBA to flag diff --git a/docs/Reference/Packages.md b/docs/Reference/Packages.md index fe9620f..088b506 100644 --- a/docs/Reference/Packages.md +++ b/docs/Reference/Packages.md @@ -26,3 +26,4 @@ These packages are built into twinBASIC and are always available, even offline. - [CustomControls Package](CustomControls/) -- owner-drawn `Waynes…` custom controls (button, form, frame, grid, label, slider, textbox, timer), the shared `Styles/` helpers that paint them, and the DESIGNER framework (interfaces, callback objects, **Canvas**, **SerializeInfo**) for authoring new custom controls - [CEF Package](CEF/) -- the **CefBrowser** control wrapping the Chromium Embedded Framework: cross-platform-ready browser embedding with a choice of three Chromium runtimes (v49 / v109 / v145); currently in BETA - [WebView2 Package](WebView2/) -- the **WebView2** control wrapping the Microsoft Edge runtime, plus its surrounding wrapper objects (request / response / headers / environment options) and the `wv2…` enumerations +- [WinEventLogLib Package](WinEventLogLib/) -- writes Windows Event Log entries from twinBASIC; the generic **EventLog**(*Of EventIds, Categories*) class handles registration, registry setup, and the per-event `ReportEventW` call, with message-table resources for *EventIds* and *Categories* synthesised into the EXE at compile time diff --git a/docs/Reference/WinEventLogLib/EventLog.md b/docs/Reference/WinEventLogLib/EventLog.md new file mode 100644 index 0000000..e6290d4 --- /dev/null +++ b/docs/Reference/WinEventLogLib/EventLog.md @@ -0,0 +1,125 @@ +--- +title: EventLog +parent: WinEventLogLib Package +permalink: /tB/Packages/WinEventLogLib/EventLog +has_toc: false +--- + +# EventLog class +{: .no_toc } + +A generic class representing one Windows Event Log source. The type parameters supply the schema of events the source can report: *T1* is an enumeration of event IDs, *T2* is an enumeration of categories. Member names from those enums become the human-readable strings the Event Viewer shows. + +Syntax: **New EventLog(Of** *T1*, *T2* **)** ( *LogName* ) + +*T1* +: *required* The enumeration type whose members name the event IDs this source can report. Passed as the *EventId* argument of [**LogSuccess**](#logsuccess) / [**LogFailure**](#logfailure). + +*T2* +: *required* The enumeration type whose members name the categories events fall into. Passed as the *CategoryId* argument of [**LogSuccess**](#logsuccess) / [**LogFailure**](#logfailure). The number of categories declared in *T2* is what [**Register**](#register) writes as the registry's `CategoryCount`. + +*LogName* +: *required* A **String** naming the event source. A leaf name like `"MyService"` is registered under the **Application** log (`Application\MyService`); a path like `"System\MyService"` is registered under the named parent log. The trailing segment is the source name — it appears in the Event Viewer's **Source** column. + +```tb +Public Enum MyEventIds + StartupOk = 1000 + StartupFailed = 1001 +End Enum + +Public Enum MyCategories + General = 1 + Network = 2 +End Enum + +Dim Log As New EventLog(Of MyEventIds, MyCategories)("MyService") +``` + +Both type arguments are required at instantiation — twinBASIC does not deduce them from the *LogName* constructor argument. See the [Generics](../../../Features/Language/Generics) page for the general rules. + +The package [overview](.) covers the install-then-log lifecycle, registry layout, and message-resource generation that surround this class. + +* TOC +{:toc} + +## Methods + +### LogFailure +{: .no_toc } + +Writes an **Error**-type entry to the log. + +Syntax: *object*.**LogFailure** *EventId*, *CategoryId* [, *AdditionalStrings* ... ] + +*EventId* +: *required* A *T1* value naming the event being reported. Becomes the numeric **Event ID** column in the Event Viewer; the corresponding member name from *T1* is used to look up the message string. + +*CategoryId* +: *required* A *T2* value naming the category the event belongs to. Becomes the numeric **Task Category** column. + +*AdditionalStrings* +: *optional* A **ParamArray** of values inserted into the event's message string at the `%1`, `%2`, … placeholders. Each value is converted to a **String** before being passed to `ReportEventW`. + +> [!NOTE] +> Despite the name, **LogFailure** writes an **Error** entry — the Windows event type `EVENTLOG_ERROR_TYPE` (= 1). It does *not* write an *Audit Failure* entry. That event type, and *Warning* and *Audit Success*, are not currently reachable through this class. + +The first call after construction lazily resolves the source handle via `RegisterEventSourceW`; if [**Register**](#register) has not been run for this *LogName*, the entry is still written but the Event Viewer cannot resolve the message strings and shows *"The description for Event ID X cannot be found"*. + +### LogSuccess +{: .no_toc } + +Writes an **Information**-type entry to the log. + +Syntax: *object*.**LogSuccess** *EventId*, *CategoryId* [, *AdditionalStrings* ... ] + +*EventId* +: *required* A *T1* value naming the event being reported. Becomes the numeric **Event ID** column in the Event Viewer. + +*CategoryId* +: *required* A *T2* value naming the category the event belongs to. + +*AdditionalStrings* +: *optional* A **ParamArray** of values inserted into the event's message string at the `%1`, `%2`, … placeholders. + +> [!NOTE] +> The Windows event type for this call is `EVENTLOG_SUCCESS` (= 0), which is the Win32 SDK's literal name for the **Information** event type — *not* an Audit Success entry. The class spells the method **LogSuccess** to track the SDK constant, but the entries you read back in `eventvwr.msc` are tagged **Information**. + +### New +{: .no_toc } + +Constructs an **EventLog** instance bound to a single source name. + +Syntax: **New EventLog(Of** *T1*, *T2* **)** ( *LogName* ) + +*LogName* +: *required* A **String** naming the source. See the top of this page for the leaf-name vs full-path syntax. + +The constructor only stores *LogName*. The first call to [**LogSuccess**](#logsuccess) / [**LogFailure**](#logfailure) lazily acquires the Win32 source handle via `RegisterEventSourceW`. [**Register**](#register) writes the registry entries the Event Viewer reads when rendering messages — it must be run separately, once, with admin rights. + +### Register +{: .no_toc } + +Writes the registry entries that declare this EXE as the message provider for the source. + +Syntax: *object*.**Register** + +Creates `HKLM\SYSTEM\CurrentControlSet\Services\EventLog\` (prepending `Application\` if *LogName* is a leaf name) and writes: + +- **EventMessageFile** = `App.ModulePath` (the running EXE) +- **CategoryMessageFile** = `App.ModulePath` +- **CategoryCount** = the largest declared value in *T2*, resolved at compile time via [**GetDeclaredMaxEnumValue**](../../Modules/HiddenModule/GetDeclaredMaxEnumValue)`(Of T2)` + +> [!IMPORTANT] +> **Register** requires administrator rights — it writes to `HKEY_LOCAL_MACHINE`. The usual pattern is to call it once from an elevated installer, not from the application's normal startup path. + +The Event Viewer renders message strings by loading **EventMessageFile** and looking up the message resource keyed by *EventId*. Because **EventMessageFile** points at `App.ModulePath`, the same EXE that calls **Register** must be the one that later calls [**LogSuccess**](#logsuccess) / [**LogFailure**](#logfailure); otherwise the Event Viewer cannot find the message strings. See [Message resources](.#message-resources) on the package landing page for how the resource is expected to be populated. + +If the registry key cannot be opened for write, **Register** raises run-time error 5 *"Failed to register event log source (\)"*. Typical causes are insufficient privileges and a *LogPath* that points at a non-existent parent log. + +The lower-level [**EventLogHelperPublic.RegisterEventLogInternal**](EventLogHelperPublic#registereventloginternal) is what **Register** delegates to; use it directly only if you need to register a source without binding it to a generic *T2* (and so without using **GetDeclaredMaxEnumValue** to derive the category count). + +## See Also + +- [WinEventLogLib package](.) -- overview, lifecycle, message-resource generation +- [EventLogHelperPublic module](EventLogHelperPublic) -- the lower-level registration helper +- [Generics feature](../../../Features/Language/Generics) -- syntax rules for generic class instantiation diff --git a/docs/Reference/WinEventLogLib/EventLogHelperPublic.md b/docs/Reference/WinEventLogLib/EventLogHelperPublic.md new file mode 100644 index 0000000..e71f78a --- /dev/null +++ b/docs/Reference/WinEventLogLib/EventLogHelperPublic.md @@ -0,0 +1,42 @@ +--- +title: EventLogHelperPublic +parent: WinEventLogLib Package +permalink: /tB/Packages/WinEventLogLib/EventLogHelperPublic +has_toc: false +--- + +# EventLogHelperPublic module +{: .no_toc } + +A single low-level helper that writes the registry entries Windows reads when rendering Event Log messages. Most projects do not call into this module directly — [**EventLog.Register**](EventLog#register) wraps the call and automatically supplies the category count from the *T2* type argument. Use **EventLogHelperPublic** only when registering a source outside the generic [**EventLog**](EventLog) class (for example, when the category count cannot be derived from a declared enum). + +* TOC +{:toc} + +## RegisterEventLogInternal + +Writes the registry entries that declare the running EXE as the message provider for an event source. + +Syntax: **EventLogHelperPublic.RegisterEventLogInternal** *LogPath*, *CategoryCount* + +*LogPath* +: *required* A **String** naming the source. A leaf name like `"MyService"` is registered under the **Application** log (rewritten internally to `"Application\MyService"`); a full path like `"System\MyService"` is registered under the named parent log. The trailing segment is the source name displayed in the Event Viewer's **Source** column. + +*CategoryCount* +: *required* A **Long** giving the number of categories declared for this source — the largest value in the corresponding category enum. Stored as the registry's `CategoryCount` DWORD; the Event Viewer uses it to bound category-string lookups in the EXE's message-table resource. + +Creates `HKLM\SYSTEM\CurrentControlSet\Services\EventLog\` and writes: + +- **EventMessageFile** = `App.ModulePath` (the running EXE; **REG_SZ**) +- **CategoryMessageFile** = `App.ModulePath` (**REG_SZ**) +- **CategoryCount** = *CategoryCount* (**REG_DWORD**) + +> [!IMPORTANT] +> **RegisterEventLogInternal** writes under `HKEY_LOCAL_MACHINE` and requires administrator rights. The usual pattern is to call it once from an elevated installer, not from the application's normal startup path. + +If the registry key cannot be opened for write, **RegisterEventLogInternal** raises run-time error 5 with the message *"Failed to register event log source (\)"*, where `` is the trailing segment of *LogPath*. Typical causes are insufficient privileges and a *LogPath* whose parent log (e.g. `"Application"`, `"System"`) does not exist. + +## See Also + +- [WinEventLogLib package](.) -- overview, lifecycle, message-resource generation +- [EventLog class](EventLog) -- the generic class whose [**Register**](EventLog#register) method wraps this helper diff --git a/docs/Reference/WinEventLogLib/index.md b/docs/Reference/WinEventLogLib/index.md new file mode 100644 index 0000000..0a1dd56 --- /dev/null +++ b/docs/Reference/WinEventLogLib/index.md @@ -0,0 +1,73 @@ +--- +title: WinEventLogLib Package +parent: Packages +grand_parent: Reference Section +nav_order: 8 +permalink: /tB/Packages/WinEventLogLib/ +has_toc: false +--- + +# WinEventLogLib Package +{: .no_toc } + +The **WinEventLogLib** built-in package writes entries to the Windows Event Log from twinBASIC. Define two enumerations — one naming the event IDs your application can report, one naming the categories those events belong to — and the generic [**EventLog**](EventLog) class handles registration, registry setup, and the per-event `ReportEventW` call. + +The package is a built-in package shipped with twinBASIC. Add it through Project → References (**Ctrl-T**) → Available Packages. + +* TOC +{:toc} + +## Lifecycle + +A typical use has three stages: + +1. **Declare** two enumerations — the event IDs and the categories — anywhere in the project. The values you assign become the numeric **Event ID** and **Category** columns visible in `eventvwr.msc`. +2. **Register** once, with administrator rights, at install time. Construct an [**EventLog**](EventLog) instance and call [**Register**](EventLog#register); this writes the source key under `HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\` and points the registry's **EventMessageFile** and **CategoryMessageFile** entries at the running EXE. Without this step, the Event Viewer shows *"The description for Event ID X cannot be found"* for every entry. +3. **Log** at runtime, without elevation. Construct the same [**EventLog**](EventLog) with the same *LogName* and call [**LogSuccess**](EventLog#logsuccess) or [**LogFailure**](EventLog#logfailure) whenever the application has something to report. + +```tb +Public Enum MyEventIds + StartupOk = 1000 + StartupFailed = 1001 + ShutdownClean = 1100 +End Enum + +Public Enum MyCategories + General = 1 + Network = 2 +End Enum + +' One-time install step (requires admin): +Sub Install() + Dim Log As New EventLog(Of MyEventIds, MyCategories)("MyService") + Log.Register +End Sub + +' Runtime use (no admin required): +Sub OnServiceStart() + Dim Log As New EventLog(Of MyEventIds, MyCategories)("MyService") + Log.LogSuccess StartupOk, General, "Service started", App.ModulePath +End Sub +``` + +The same EXE that calls [**Register**](EventLog#register) must be the one that calls [**LogSuccess**](EventLog#logsuccess) / [**LogFailure**](EventLog#logfailure) — the registered **EventMessageFile** points at `App.ModulePath`, and the Event Viewer reads message strings out of that file when rendering entries. + +## Message resources + +The Windows Event Log stores only numeric **Event ID** and **Category** values; the human-readable strings live in a message-table resource embedded in the EXE pointed to by the registered **EventMessageFile** / **CategoryMessageFile** entries. Without this resource the Event Viewer cannot render entries and instead shows *"The description for Event ID X cannot be found"*. + +For the generic [**EventLog**](EventLog)`(Of T1, T2)` class, the *T1* (event IDs) and *T2* (categories) enum declarations are the source of those strings — the class points the registry at the running EXE and assumes the EXE carries a message-table resource keyed by the enum member values. Authoring the resource yourself (a `.mc` file fed to `mc.exe`) and embedding it in the EXE is one route; the [**EventLog**](EventLog) class is designed to interoperate with whatever mechanism populates that resource for the *T1* / *T2* member names. + +## Log Type + +[**LogSuccess**](EventLog#logsuccess) and [**LogFailure**](EventLog#logfailure) are the only entry points currently exposed; they write **Information**-type and **Error**-type entries respectively. The names follow the Win32 SDK's `EVENTLOG_SUCCESS` (= 0, the *information* event type) and `EVENTLOG_ERROR_TYPE` (= 1) constants verbatim — *not* the Audit Success / Audit Failure event types familiar from the Security log. + +The three other Windows Event Log entry types — **Warning**, **Audit Success**, and **Audit Failure** — are not yet reachable through the public API. + +## Classes + +- [EventLog](EventLog) -- the generic event-log source — open / register / log entries against one event log, parameterised by an event-ID enum and a category enum + +## Modules + +- [EventLogHelperPublic](EventLogHelperPublic) -- the low-level registry helper underlying [**EventLog.Register**](EventLog#register); call it directly only when you need to supply a category count without using the generic class