XP11: whole suite on net40 — Console + vPOD run on XP SP3 through Win11

The Launcher's XP11 port (8730b9b) now extends to everything: one net40
flavor across Console, vPOD, Contract, and SecureConfig (Newtonsoft.Json
everywhere; the net48/System.Text.Json legs and their #if splits are gone
since nothing consumed them).

Console (net40, single TFM like the Launcher):
- The ~31 BinaryFormatter bitmap blobs in the .resx files became raw
  embedded files under assets/icons/ (extracted byte-faithfully via a
  serialization surrogate — the animated square_throbber.gif survives),
  loaded by Properties.Resources.EmbeddedBitmap/EmbeddedIcon. Reason:
  System.Resources.Extensions' DeserializingResourceReader is net461+
  and cannot load on net40. Strings stay in the .resx.
- IReadOnlyList -> IList in AppRegistry (net45+ interface).

vPOD (net40, single TFM):
- Zip extraction now shares the Launcher's MiniZip.cs (linked source), so
  the diff-test install round-trip exercises it against ZipArchive zips.
- RPC args as JTokens; LaunchApps.json persistence via Newtonsoft;
  Thread.VolatileRead instead of Volatile.Read.

Contract/SecureConfig: net40-only; Client/** (PodManagerConnection) now
ships in the one build. The Launcher package gains
TeslaSecureConfiguration.dll as a dependency of the client half.

Tests: the net48 xunit host loads the net40 assemblies (both CLR4), so
the suite exercises exactly what ships — 106/106 green. Also verified
live: net40 console provisioned, managed, and ran a full RP mission
against net40 vPOD (beacon/passphrase/RSA, 53290 RPC, egg load,
Run/Stop Mission).

Version: 4.11.4.3 across Launcher, Console, and vPOD (vPOD joins the
suite version line; was 1.0.0). Ship the dotNetFx40 redistributable in
Launcher/assets for XP-era pods.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-11 21:01:34 -05:00
co-authored by Claude Fable 5
parent eefb8054e0
commit 91640dcbf2
61 changed files with 250 additions and 419 deletions
+2 -2
View File
@@ -8,9 +8,9 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2009")]
[assembly: AssemblyConfiguration("")]
[assembly: Guid("581ca4b6-a91c-4d24-b9b5-207f3b5da379")]
[assembly: AssemblyFileVersion("4.11.4.1")]
[assembly: AssemblyFileVersion("4.11.4.3")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: AssemblyTitle("Tesla Console")]
[assembly: AssemblyDescription("All code and UI property of Virtual World Entertainment.\r\n\r\nDeveloped by Elsewhen Studios, LLC in association with VGCorps, LLC.\r\n\r\nElsewhen Studios and the Elsewhen Wormhole are trademarks of Elsewhen Studios, LLC\r\n\r\nIncludes the WeifenLuo DockingPane library. Copyright © 2007 Weifen Luo (email: weifenluo@yahoo.com). Licensed under the MIT License - details can be found in WeifenLuo.txt included in this installation.")]
[assembly: AssemblyVersion("4.11.4.1")]
[assembly: AssemblyVersion("4.11.4.3")]
+19 -14
View File
@@ -39,13 +39,14 @@ The console references these assemblies. Most are vendored as binaries under
Two of these are no longer vendored binaries — they are built from source and
shared across the suite:
- `TeslaConsoleLaunchLib``../Contract/Tesla.Contract.csproj`, a net48 project: the
single source of truth for the Console↔Launcher RPC contract (wire types, the
- `TeslaConsoleLaunchLib``../Contract/Tesla.Contract.csproj` (net40, like the
whole suite since XP11): the single source of truth for the
Console↔Launcher RPC contract (wire types, the
`PodManagerConnection` client, and the framed-JSON `PodRpc` protocol), shared with the
Launcher Service. The assembly keeps the
Launcher. The assembly keeps the
`TeslaConsoleLaunchLib` name so the original-exe baseline still resolves in the
differential tests; the wire no longer embeds assembly names (see RPC note below).
- `TeslaSecureConfiguration``../SecureConfig/Tesla.SecureConfig.csproj` (net48),
- `TeslaSecureConfiguration``../SecureConfig/Tesla.SecureConfig.csproj` (net40),
the first-boot provisioning protocol (UDP beacons, OFB crypto, RSA key exchange).
The original `TeslaSecureConfiguration.dll` is retained under `lib/` as the baseline
@@ -55,14 +56,16 @@ decompiled to source the same way if full-source builds are needed.
### Console ↔ Launcher RPC (no BinaryFormatter)
The pod-management channel (TCP 53290) runs **length-prefixed System.Text.Json**
The pod-management channel (TCP 53290) runs **length-prefixed JSON**
frames over the existing OFB-encrypted stream — see `Contract/PodRpcProtocol.cs`,
shared verbatim by both ends. This replaced the original `BinaryFormatter` +
shared verbatim by both ends (Newtonsoft.Json — net40 has no System.Text.Json).
This replaced the original `BinaryFormatter` +
serialized-`MethodBase` scheme (a remote-code-execution sink, and what had pinned the
Launcher to an old runtime); dispatch is now by method-name string. The Launcher
Service/Agent target **net48**, same as the Console. Note the Console still uses
`BinaryFormatter` for *local* disk persistence (`Site` config, mission results) — that
is local file I/O on net48, not the network surface, and is intentionally left alone.
Launcher to an old runtime); dispatch is now by method-name string. The Launcher and
the Console both target **net40** (XP11: XP SP3 through Windows 11). Note the Console
still uses `BinaryFormatter` for *local* disk persistence (`Site` config, mission
results) — that is local file I/O, not the network surface, and is intentionally
left alone.
## Layout
@@ -72,8 +75,10 @@ and still build and run.
```
TeslaConsole/
*.cs, TeslaConsole.*/ decompiled source (by namespace)
*.resx, app.ico embedded resources + icon
TeslaConsole.csproj net48 project
*.resx, app.ico string resources + icon
assets/icons/ UI images (raw originals, embedded as manifest resources —
the resx BinaryFormatter blobs cannot build for net40)
TeslaConsole.csproj net40 project (XP11: runs on XP SP3 through Windows 11)
RedPlanet/ runtime content (RPConfig.xml, RPStrings.xml) — copied to output
images/ source art (pod art / maps / vehicles) — reference only
installer_banner.bmp installer artwork — reference only
@@ -84,14 +89,14 @@ TeslaConsole/
## Building
Requirements: .NET SDK (6.0+) — the `Microsoft.NETFramework.ReferenceAssemblies`
NuGet package supplies the net48 reference assemblies, so a standalone Framework
NuGet package supplies the net40 reference assemblies, so a standalone Framework
targeting pack is **not** required.
```
dotnet build TeslaConsole.csproj -c Release
```
Output: `bin/Release/net48/TeslaConsole.exe` (with `RedPlanet/` and all
Output: `bin/Release/net40/TeslaConsole.exe` (with `RedPlanet/` and all
dependency DLLs copied alongside it).
## Runtime content
File diff suppressed because one or more lines are too long
+65 -208
View File
@@ -1,8 +1,10 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Runtime.CompilerServices;
@@ -17,6 +19,15 @@ internal class Resources
private static CultureInfo resourceCulture;
// XP11: the images that used to live in the .resx as BinaryFormatter blobs now
// ship as raw embedded files (logical name "TeslaConsole.Icons.<file>", original
// bytes — see Console\assets\icons\). Building those blobs requires
// System.Resources.Extensions' DeserializingResourceReader at runtime, which is
// net461+ and cannot load on the XP-compatible net40. Strings stay in the .resx.
// Instances are cached like ResourceManager.GetObject cached them: one shared
// object per name.
private static readonly Dictionary<string, object> imageCache = new Dictionary<string, object>();
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager
{
@@ -43,262 +54,108 @@ internal class Resources
}
}
internal static Bitmap Add
internal static Bitmap EmbeddedBitmap(string file)
{
get
lock (imageCache)
{
object @object = ResourceManager.GetObject("Add", resourceCulture);
return (Bitmap)@object;
object image;
if (!imageCache.TryGetValue(file, out image))
{
// Deliberately not disposed: GDI+ decodes lazily (e.g. the animated
// GIF's frames), so the stream must outlive the Bitmap. It is an
// UnmanagedMemoryStream over the mapped assembly image — no handle.
Stream stream = typeof(Resources).Assembly.GetManifestResourceStream("TeslaConsole.Icons." + file);
image = new Bitmap(stream);
imageCache.Add(file, image);
}
return (Bitmap)image;
}
}
internal static Bitmap Blank
internal static Icon EmbeddedIcon(string file)
{
get
lock (imageCache)
{
object @object = ResourceManager.GetObject("Blank", resourceCulture);
return (Bitmap)@object;
object icon;
if (!imageCache.TryGetValue(file, out icon))
{
using (Stream stream = typeof(Resources).Assembly.GetManifestResourceStream("TeslaConsole.Icons." + file))
{
icon = new Icon(stream);
}
imageCache.Add(file, icon);
}
return (Icon)icon;
}
}
internal static Bitmap DeleteHS
{
get
{
object @object = ResourceManager.GetObject("DeleteHS", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap Add => EmbeddedBitmap("Add.png");
internal static Bitmap Error
{
get
{
object @object = ResourceManager.GetObject("Error", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap Blank => EmbeddedBitmap("Blank.png");
internal static Bitmap DeleteHS => EmbeddedBitmap("DeleteHS.png");
internal static Bitmap Error => EmbeddedBitmap("Error.bmp");
internal static string ErrorReportsDir => ResourceManager.GetString("ErrorReportsDir", resourceCulture);
internal static Bitmap install
{
get
{
object @object = ResourceManager.GetObject("install", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap install => EmbeddedBitmap("install.png");
internal static Bitmap openHS
{
get
{
object @object = ResourceManager.GetObject("openHS", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap openHS => EmbeddedBitmap("openHS.png");
internal static Bitmap Play
{
get
{
object @object = ResourceManager.GetObject("Play", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap Play => EmbeddedBitmap("Play.png");
internal static Bitmap PodBad16
{
get
{
object @object = ResourceManager.GetObject("PodBad16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodBad16 => EmbeddedBitmap("PodBad16.png");
internal static Bitmap PodBad32
{
get
{
object @object = ResourceManager.GetObject("PodBad32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodBad32 => EmbeddedBitmap("PodBad32.png");
internal static string PodBadImageKey => ResourceManager.GetString("PodBadImageKey", resourceCulture);
internal static Bitmap PodGo16
{
get
{
object @object = ResourceManager.GetObject("PodGo16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodGo16 => EmbeddedBitmap("PodGo16.png");
internal static Bitmap PodGo32
{
get
{
object @object = ResourceManager.GetObject("PodGo32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodGo32 => EmbeddedBitmap("PodGo32.png");
internal static string PodGoImageKey => ResourceManager.GetString("PodGoImageKey", resourceCulture);
internal static Bitmap PodOffline16
{
get
{
object @object = ResourceManager.GetObject("PodOffline16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodOffline16 => EmbeddedBitmap("PodOffline16.png");
internal static Bitmap PodOffline32
{
get
{
object @object = ResourceManager.GetObject("PodOffline32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodOffline32 => EmbeddedBitmap("PodOffline32.png");
internal static string PodOfflineImageKey => ResourceManager.GetString("PodOfflineImageKey", resourceCulture);
internal static Bitmap PodOfflineQuestion32
{
get
{
object @object = ResourceManager.GetObject("PodOfflineQuestion32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodOfflineQuestion32 => EmbeddedBitmap("PodOfflineQuestion32.png");
internal static Bitmap PodOnline16
{
get
{
object @object = ResourceManager.GetObject("PodOnline16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodOnline16 => EmbeddedBitmap("PodOnline16.png");
internal static Bitmap PodOnline32
{
get
{
object @object = ResourceManager.GetObject("PodOnline32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodOnline32 => EmbeddedBitmap("PodOnline32.png");
internal static string PodOnlineImageKey => ResourceManager.GetString("PodOnlineImageKey", resourceCulture);
internal static Bitmap PodQuestion16
{
get
{
object @object = ResourceManager.GetObject("PodQuestion16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodQuestion16 => EmbeddedBitmap("PodQuestion16.png");
internal static Bitmap PodQuestion32
{
get
{
object @object = ResourceManager.GetObject("PodQuestion32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodQuestion32 => EmbeddedBitmap("PodQuestion32.png");
internal static string PodQuestionImageKey => ResourceManager.GetString("PodQuestionImageKey", resourceCulture);
internal static Bitmap PodRun16
{
get
{
object @object = ResourceManager.GetObject("PodRun16", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodRun16 => EmbeddedBitmap("PodRun16.png");
internal static Bitmap PodRun32
{
get
{
object @object = ResourceManager.GetObject("PodRun32", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap PodRun32 => EmbeddedBitmap("PodRun32.png");
internal static string PodRunImageKey => ResourceManager.GetString("PodRunImageKey", resourceCulture);
internal static Bitmap Power
{
get
{
object @object = ResourceManager.GetObject("Power", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap Power => EmbeddedBitmap("Power.png");
internal static Bitmap RefreshDoc
{
get
{
object @object = ResourceManager.GetObject("RefreshDoc", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap RefreshDoc => EmbeddedBitmap("RefreshDoc.png");
internal static Bitmap saveHS
{
get
{
object @object = ResourceManager.GetObject("saveHS", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap saveHS => EmbeddedBitmap("saveHS.png");
internal static Bitmap square_throbber
{
get
{
object @object = ResourceManager.GetObject("square_throbber", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap square_throbber => EmbeddedBitmap("square_throbber.gif");
internal static Bitmap Stop
{
get
{
object @object = ResourceManager.GetObject("Stop", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap Stop => EmbeddedBitmap("Stop.png");
internal static Icon swirl
{
get
{
object @object = ResourceManager.GetObject("swirl", resourceCulture);
return (Icon)@object;
}
}
internal static Icon swirl => EmbeddedIcon("swirl.ico");
internal static Bitmap WebRefreshHH
{
get
{
object @object = ResourceManager.GetObject("WebRefreshHH", resourceCulture);
return (Bitmap)@object;
}
}
internal static Bitmap WebRefreshHH => EmbeddedBitmap("WebRefreshHH.png");
internal Resources()
{
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+18 -7
View File
@@ -3,8 +3,13 @@
<AssemblyName>TeslaConsole</AssemblyName>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<OutputType>WinExe</OutputType>
<UseWindowsForms>True</UseWindowsForms>
<TargetFramework>net48</TargetFramework>
<!-- net40 (XP11): the newest .NET Framework that installs on Windows XP SP3;
net40 assemblies load in-place on the 4.8 runtime in Win10/11, so this ONE
exe covers XP SP3 through Windows 11 — same deal as the Launcher. The
original console was net20, so the decompiled core needs nothing newer.
WinForms comes via plain framework references (UseWindowsForms is not
wired up for net40). -->
<TargetFramework>net40</TargetFramework>
<LangVersion>Preview</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<ApplicationIcon>app.ico</ApplicationIcon>
@@ -12,17 +17,21 @@
<!-- Decompiled from the original net20 TeslaConsole.exe; legacy WinForms 2.0 sources -->
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<!-- .resx files embed BinaryFormatter-serialized bitmaps (non-string resources) -->
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
<!-- CS0649: decompiled WinForms designer 'components' fields are never assigned -->
<NoWarn>$(NoWarn);CS0649</NoWarn>
</PropertyGroup>
<ItemGroup>
<!-- net48 reference assemblies so the project builds without a full targeting pack installed -->
<!-- .NET Framework reference assemblies so the project builds without a full targeting pack installed -->
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
<!-- Required to read the pre-serialized binary resources above -->
<PackageReference Include="System.Resources.Extensions" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<!-- The UI images, embedded as their raw original bytes (extracted 1:1 from the
old .resx BinaryFormatter blobs). Loaded by Properties.Resources.EmbeddedBitmap/
EmbeddedIcon: the .resx blob route needs System.Resources.Extensions at
runtime, which is net461+ and cannot load on net40/XP. -->
<EmbeddedResource Include="assets\icons\*.*" LogicalName="TeslaConsole.Icons.%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
@@ -48,6 +57,8 @@
</ItemGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Drawing" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Xml" />
<Reference Include="System.ServiceProcess" />
+3 -1
View File
@@ -80,7 +80,9 @@ public static class AppRegistry
private static readonly Dictionary<Guid, ProductDefinition> mById = new Dictionary<Guid, ProductDefinition>();
public static IReadOnlyList<ProductDefinition> Products => mProducts;
// IList, not IReadOnlyList: the read-only interfaces are net45+ and the
// XP11 console targets net40. Callers only enumerate/index it.
public static IList<ProductDefinition> Products => mProducts;
public static string CatalogPath =>
Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "RedPlanet\\Apps.xml");
+2 -2
View File
@@ -214,7 +214,7 @@ internal class SitePanel : DockContent
this.tsbManageSite.Text = "Manage Site";
this.tsbManageSite.Click += new System.EventHandler(tsbManageSite_Click);
this.mPowerDropDown.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[5] { this.mRestartAllPods, this.mShutdownAllPods, this.mPowerSeparator, this.mRestartAllCheckedPods, this.mShutdownAllCheckedPods });
this.mPowerDropDown.Image = (System.Drawing.Image)resources.GetObject("mPowerDropDown.Image");
this.mPowerDropDown.Image = TeslaConsole.Properties.Resources.EmbeddedBitmap("SitePanel.mPowerDropDown.Image.png");
this.mPowerDropDown.ImageTransparentColor = System.Drawing.Color.Magenta;
this.mPowerDropDown.Name = "mPowerDropDown";
this.mPowerDropDown.Size = new System.Drawing.Size(69, 22);
@@ -302,7 +302,7 @@ internal class SitePanel : DockContent
this.lblPodName.Text = "Mistress Quickly";
this.picRefresh.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
this.picRefresh.Cursor = System.Windows.Forms.Cursors.Hand;
this.picRefresh.Image = (System.Drawing.Image)resources.GetObject("picRefresh.Image");
this.picRefresh.Image = TeslaConsole.Properties.Resources.EmbeddedBitmap("SitePanel.picRefresh.Image.png");
this.picRefresh.Location = new System.Drawing.Point(308, 3);
this.picRefresh.Name = "picRefresh";
this.picRefresh.Size = new System.Drawing.Size(32, 32);
+2 -2
View File
@@ -758,7 +758,7 @@ public class TeslaConsoleForm : Form
this.mRPPrintPreviewDialog.AutoScrollMinSize = new System.Drawing.Size(0, 0);
this.mRPPrintPreviewDialog.ClientSize = new System.Drawing.Size(400, 300);
this.mRPPrintPreviewDialog.Enabled = true;
this.mRPPrintPreviewDialog.Icon = (System.Drawing.Icon)resources.GetObject("mRPPrintPreviewDialog.Icon");
this.mRPPrintPreviewDialog.Icon = TeslaConsole.Properties.Resources.EmbeddedIcon("TeslaConsoleForm.mRPPrintPreviewDialog.Icon.ico");
this.mRPPrintPreviewDialog.Name = "printPreviewDialog1";
this.mRPPrintPreviewDialog.Visible = false;
this.mRPPrintDialog.UseEXDialog = true;
@@ -773,7 +773,7 @@ public class TeslaConsoleForm : Form
base.ClientSize = new System.Drawing.Size(1168, 591);
base.Controls.Add(this.mMainDockPanel);
base.Controls.Add(this.mMenu);
base.Icon = (System.Drawing.Icon)resources.GetObject("$this.Icon");
base.Icon = TeslaConsole.Properties.Resources.EmbeddedIcon("TeslaConsoleForm.$this.Icon.ico");
base.IsMdiContainer = true;
base.MainMenuStrip = this.mMenu;
base.Name = "TeslaConsoleForm";
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

+5 -4
View File
@@ -2,9 +2,10 @@
:: =============================================================================
:: TeslaConsole - Build ^& Package
:: =============================================================================
:: Publishes the console (net48, framework-dependent) into TeslaConsole\App and
:: assembles the installable package (App\ + install.bat) next to it. net48 is
:: in-box on Windows 10/11, so the target control PC needs no runtime install.
:: Publishes the console (net40, framework-dependent - XP11: runs on XP SP3
:: through Windows 11) into TeslaConsole\App and assembles the installable
:: package (App\ + install.bat) next to it. The 4.x runtime is in-box on
:: Windows 10/11; an XP-era control PC needs dotNetFx40_Full_x86_x64.exe once.
::
:: Requirements: .NET SDK (6.0+) to drive the build; internet for first restore.
::
@@ -24,7 +25,7 @@ set ZIP=%ROOT%dist\TeslaConsole-pkg.zip
echo.
echo ============================================================
echo TeslaConsole - Build ^& Package (net48, framework-dependent)
echo TeslaConsole - Build ^& Package (net40, framework-dependent)
echo Output : %BUILD_DIR%
echo ============================================================
echo.
@@ -6,7 +6,8 @@ namespace TeslaConsole.DiffTests
/// <summary>
/// Locates the two assemblies under comparison:
/// * Original - original/TeslaConsole.exe (the lost-source reference baseline)
/// * Recovered - bin/Release/net48/TeslaConsole.exe (freshly built reconstruction)
/// * Recovered - bin/Release/net40/TeslaConsole.exe (freshly built reconstruction;
/// net40 since XP11 — loads fine in this net48 test host, both are CLR4)
/// </summary>
public static class AssemblyPaths
{
@@ -39,8 +40,8 @@ namespace TeslaConsole.DiffTests
private static string FindRecoveredExe()
{
string release = Path.Combine(RepoRoot, "bin", "Release", "net48", "TeslaConsole.exe");
string debug = Path.Combine(RepoRoot, "bin", "Debug", "net48", "TeslaConsole.exe");
string release = Path.Combine(RepoRoot, "bin", "Release", "net40", "TeslaConsole.exe");
string debug = Path.Combine(RepoRoot, "bin", "Debug", "net40", "TeslaConsole.exe");
// Test whichever build is freshest, so a stale config never silently wins.
string best = null;
@@ -47,7 +47,7 @@ namespace TeslaConsole.DiffTests
Assert.Contains("TeslaConsole", _fx.Original.AssemblyFullName);
Assert.Contains("TeslaConsole", _fx.Recovered.AssemblyFullName);
Assert.Contains("4.11.3.37076", _fx.Original.AssemblyFullName);
Assert.Contains("4.11.4.1", _fx.Recovered.AssemblyFullName);
Assert.Contains("4.11.4.3", _fx.Recovered.AssemblyFullName);
}
// ---- RPStrings.GetTimeString: mm:ss formatting with 0.5s rounding ----
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Tesla.Net;
using Xunit;
@@ -29,8 +28,8 @@ namespace TeslaConsole.DiffTests
var req = PodRpc.ReadRequest(ms);
Assert.Equal("KillApp", req.Method);
Assert.Equal(2, req.Args.Count);
Assert.Equal(Key, req.Args[0].GetGuid());
Assert.Equal(4242, req.Args[1].GetInt32());
Assert.Equal(Key, req.Args[0].ToObject<Guid>(PodRpc.JsonOptions));
Assert.Equal(4242, req.Args[1].ToObject<int>(PodRpc.JsonOptions));
}
[Fact]
@@ -150,7 +149,7 @@ namespace TeslaConsole.DiffTests
ms.Position = 0;
var resp = PodRpc.ReadResponse(ms);
Assert.Null(resp.Error);
return resp.Result.Deserialize<T>(PodRpc.JsonOptions);
return resp.Result.ToObject<T>(PodRpc.JsonOptions);
}
}
}
@@ -76,7 +76,9 @@ dotnet test tests/TeslaConsole.DiffTests/TeslaConsole.DiffTests.csproj
```
A project reference builds the reconstruction first, and the suite always tests
the most recently built `bin/{Debug,Release}/net48/TeslaConsole.exe`.
the most recently built `bin/{Debug,Release}/net40/TeslaConsole.exe` (net40 since
the XP11 port; the net48 test host loads it fine — both are CLR4, so the whole
process runs the net40/Newtonsoft stack that ships).
## Scope / limitations
@@ -50,7 +50,9 @@
</ProjectReference>
<!-- The source-built wire contract (emits TeslaConsoleLaunchLib.dll). Referenced
directly so WireContractCompatTests can construct Tesla.Net types and compare
their BinaryFormatter output against the original vendored DLL. -->
their BinaryFormatter output against the original vendored DLL. net40 (like
everything under test since XP11); loads fine in this net48 host — both are
CLR4 — so the suite exercises the exact Newtonsoft stack that ships. -->
<ProjectReference Include="..\..\..\Contract\Tesla.Contract.csproj" />
<!-- The source-built secure-config (emits TeslaSecureConfiguration.dll), for
SecureConfigCompatTests' byte-identity checks vs the original vendored DLL. -->