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>
@@ -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")]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 938 B |
|
After Width: | Height: | Size: 693 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 454 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 501 B |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 997 B |
|
After Width: | Height: | Size: 772 B |
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 404 B |
|
After Width: | Height: | Size: 138 KiB |
@@ -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. -->
|
||||
|
||||