Migrate the setup tools to .NET 8 and replace the VB6 migration tools - #15
Merged
Conversation
DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer and Shared move from .NET Framework 4.8.1 old-style projects to SDK-style net8.0-windows WinForms, following the ControlPanel conventions (x64, framework-dependent win-x64, pinned bin\$(Configuration) output, version 6.2.11). - The hMailServer COM API is now consumed through a checked-in tlbimp wrapper (source/Tools/Interop/Interop.hMailServer.dll, regeneration documented alongside) instead of a build-time COMReference, so the tools build with plain dotnet build on machines without a registered typelib - including hosted CI. - New Shared.ToolApplication.Initialize() pins the WinForms defaults the dialogs were designed against (Microsoft Sans Serif 8.25pt, system-DPI awareness) so the absolute layouts keep their metrics. - formEnterPassword's help link sets UseShellExecute, required to open a URL on .NET 8; DBSetupQuick resolves DBUpdater.exe relative to the executable instead of the working directory. - AssemblyInfo/Settings/Resources boilerplate, app.config files and the per-project solutions are superseded by the SDK and removed; "hMailServer Tools.sln" is regenerated listing the five projects. Validated: dotnet build clean (0 warnings); DBUpdater /SilentIfOk and DBSetupQuick /silent exit 0 against the live 6.2.11 server from a merged Bin layout; DBSetup shows the password dialog with correct rendering.
The Migration folder held four VB6 wizards (ArgoSoft, IMail, MboxImporter, Textfile) plus the C# Mercury tool. None could be built: the VB6 projects reference Common\VB sources that are not in the repository, and Mercury links Common\Admin files that were moved to Tools\Shared long ago. ArgoSoft, IMail and Mercury migrate from products that have been dead for roughly two decades and are retired outright. The two with lasting value return as one supported tool, source/Tools/ImportTool (net8.0-windows WinForms, same conventions as the other tools): - Accounts from a text file: same comma-separated format (name,password,maxsize-MB, # comments), now with trimmed fields, strict 3-field validation, per-line error reporting instead of a crash, and a created/updated/failed summary. Upsert behaviour is kept and now stated in the UI. - Messages from mbox files: one IMAP folder per mbox file (extension stripped, "inbox" maps to INBOX). The importer streams the file and goes through the supported COM API - Utilities.ImportMessageFromFileToIMAPFolder - instead of the VB6 tool's raw MySQL INSERTs against a decades-old schema. The new MboxParser fixes every defect documented in the VB6 version: the last message of a file is no longer dropped, CRLF mboxes parse correctly, Thunderbird "From - " lines are recognised, mboxrd ">From " quoting is reversed, and no SMTP dot-stuffing corrupts stored messages. Verified against crafted LF/CRLF/single-message/mboxrd/From-in-body samples.
Installer:
- The database tools now ship as dotnet publish folders: DBUpdater,
DBSetup and DBSetupQuick merge into {app}\Bin (identical shared
files), DataDirectorySynchronizer keeps its Addons folder, and the new
ImportTool ships under {app}\Addons\ImportTool with a Start Menu icon.
- The .NET 8 Desktop Runtime becomes a prerequisite of the server
component, not just the Control Panel: the runtime package is now
gated "server controlpanel", and a new InstallDotNetRuntime() runs at
the start of RunPostInstallTasks - the database tools execute from
[Code] at ssPostInstall, which is before the [Run] section installs
the runtime, so without this a server-only install would run them on
a machine with no runtime.
- The .NET Framework 4.5 InitializeSetup gate is removed; it guarded
the last .NET Framework tools.
- {app}\Bin keeps a copy of Interop.hMailServer.dll (now sourced from
the checked-in source/Tools/Interop wrapper) for external .NET
scripts, gated "server admintools". The separate Shared.dll entry for
admintools-only installs is dropped - nothing in that component used
a WinForms helper library.
Build/CI:
- build/build-tools.ps1 publishes all five tools; README and AGENTS.md
document it as the tools build entry point.
- ci.yml gains a "Build .NET tools" job (dotnet build -warnaserror +
publish smoke check). The tools build against the checked-in interop,
so hosted runners need no registered typelib - this closes the CI
blind spot where test/tool project breakage was invisible.
- MboxParser now normalizes line endings to CRLF when writing message
bytes: the server's message pipeline requires CRLF, so an LF-only
(Unix) mbox previously produced stored .eml files the server could
not parse. Verified end to end: an LF-only mbox imports with correct
subjects, senders, dates and bodies.
- ImportTool writes each message as {account}\XY\{GUID}.eml (the
server's on-disk convention) so ImportMessageFromFileToIMAPFolder
never relocates the file; previously a failure after the server's
internal move orphaned the message at a path the cleanup could not
see. Cleanup also no longer aborts the import on non-IO errors.
- ucWizard.ShowPage restores the pre-validation button states instead
of force-enabling all three; force-enabling let a failed validation
on the first page enable Previous, and clicking it crashed with
ShowPage(-1). Latent for DBSetup (its first page never fails);
ImportTool's first pages validate, making it reachable.
- ucMboxSelect skips mail-client index files (.msf/.dat) so a
Thunderbird profile folder imports cleanly (Inbox.msf previously
collided with the Inbox mbox and imported garbage).
- ImportTool refuses /silent - the shared wizard would otherwise
auto-run all pages with empty selections.
- InstallDotNetRuntime checks the runtime bundle's exit code (0/3010 =
success); Exec only reports launch failures, so a failed install
previously passed silently and the DB tools then could not start.
MinVersion raised to Windows 10 1607, the .NET 8 runtime's floor -
on older Windows the runtime install fails and the server would be
left without a database.
- build-tools.ps1 cleans each publish folder before publishing;
dotnet publish never removes orphans, and the installer wildcards
the folder's entire contents into {app}\Bin.
Findings produced by a five-lens adversarial review (12 raised, 9
confirmed after refutation passes, all fixed).
| { | ||
| using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) | ||
| { | ||
| var current = new MemoryStream(); |
| if (messageStarted) | ||
| { | ||
| onMessage(TrimTrailingBlankLine(current)); | ||
| current = new MemoryStream(); |
| /// </summary> | ||
| private static byte[] ReadLine(Stream stream) | ||
| { | ||
| var buffer = new MemoryStream(); |
| { | ||
| System.Windows.Forms.Application.EnableVisualStyles(); | ||
| System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); | ||
| System.Windows.Forms.Application.SetDefaultFont(new Font("Microsoft Sans Serif", 8.25f)); |
| var domain = Globals.GetApp().Domains.get_ItemByName((string) comboDomains.SelectedItem); | ||
| var account = domain.Accounts.get_ItemByAddress(address); | ||
|
|
||
| SelectedAccount = address; |
| var account = domain.Accounts.get_ItemByAddress(address); | ||
|
|
||
| SelectedAccount = address; | ||
| SelectedAccountID = account.ID; |
| return false; | ||
| } | ||
|
|
||
| SelectedFile = textFile.Text; |
| } | ||
|
|
||
| SelectedFile = textFile.Text; | ||
| SelectedDomain = (string) comboDomains.SelectedItem; |
Comment on lines
+113
to
+117
| foreach (var b in line) | ||
| { | ||
| if (b != '\r' && b != '\n') | ||
| return false; | ||
| } |
Comment on lines
+31
to
+34
| catch (Exception ex) | ||
| { | ||
| AddToLog("The import failed: " + ex.Message); | ||
| } |
chrisholloway5
force-pushed
the
net8-tools
branch
from
August 10, 2026 19:15
4e169a3 to
51668f1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the .NET modernization of the C# tooling: the five setup-tool projects (DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer, Shared) move from .NET Framework 4.8.1 to SDK-style net8.0-windows, and the unbuildable VB6-era
source/Migrationtools are replaced by one supported .NET 8 ImportTool (accounts from text files, messages from mbox files).Key design points
source/Tools/Interop/Interop.hMailServer.dll(tlbimp wrapper, regeneration documented) instead of a build-time COMReference — so they build with plaindotnet buildanywhere, and CI gains a tools job with warnings-as-errors, closing the blind spot where tool/test project breakage was invisible to PR checks.ToolApplication.Initialize()pins the WinForms defaults the dialogs were designed against (Microsoft Sans Serif 8.25pt, system-DPI)./silent,password:,/SilentIfOkand window titles are unchanged (verified against the installer's invocations and VMTestRunner's TestEnvironments.json).From -lines, mboxrd quoting, dot-stuffing corruption, SQL-injection-laden direct-MySQL writes (now viaUtilities.ImportMessageFromFileToIMAPFolder).Validation
dotnet buildclean, zero warnings, all six projects./SilentIfOkand DBSetupQuick/silentexit 0 against the live 6.2.11 server from a merged Bin layout; DBSetup renders correctly.