diff --git a/.appveyor.yml b/.appveyor.yml index aac253a..65114a4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,6 +25,7 @@ after_build: #- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Toolkit\bin\x86\%CONFIGURATION%\* artifacts\ - cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Service\bin\x86\%CONFIGURATION%\* artifacts\ - cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Launcher\bin\x86\%CONFIGURATION%\* artifacts\ + - cmd: xcopy /s /y WelsonJS.Toolkit\Catswords.Phantomizer\bin\%CONFIGURATION%\netstandard2.0\* artifacts\ - cmd: nuget pack WelsonJS.Toolkit\WelsonJS.Toolkit\ -properties Configuration=%CONFIGURATION% -properties Platform=x86 -OutputDirectory artifacts\ - ps: Start-BitsTransfer -Source "https://catswords.blob.core.windows.net/welsonjs/welsonjs_setup_unsigned.exe" -Destination "artifacts\welsonjs_setup.exe" - ps: Start-BitsTransfer -Source "https://catswords.blob.core.windows.net/welsonjs/chakracore-build/x86_release/ChakraCore.dll" -Destination "artifacts\ChakraCore.dll" diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/AssemblyLoader.cs b/WelsonJS.Toolkit/Catswords.Phantomizer/AssemblyLoader.cs similarity index 84% rename from WelsonJS.Toolkit/WelsonJS.Launcher/AssemblyLoader.cs rename to WelsonJS.Toolkit/Catswords.Phantomizer/AssemblyLoader.cs index 28575be..abe4c2a 100644 --- a/WelsonJS.Toolkit/WelsonJS.Launcher/AssemblyLoader.cs +++ b/WelsonJS.Toolkit/Catswords.Phantomizer/AssemblyLoader.cs @@ -1,10 +1,11 @@ -๏ปฟ// AssemblyLoader.cs -// SPDX-License-Identifier: GPL-3.0-or-later +๏ปฟ// AssemblyLoader.cs (Catswords.Phantomizer) +// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: Namhyeon Go , 2025 Catswords OSS and WelsonJS Contributors // https://github.com/gnh1201/welsonjs // using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Net; @@ -12,14 +13,14 @@ using System.Net.Http; using System.Reflection; using System.Runtime.InteropServices; -namespace WelsonJS.Launcher +namespace Catswords.Phantomizer { /// /// Network-aware loader for managed (.NET) and native (C/C++) binaries. /// - Managed assemblies resolve via AssemblyResolve /// - Native modules explicitly loaded via LoadNativeModules(...) /// - All DLLs must have valid Authenticode signatures - /// - Cached at: %APPDATA%\WelsonJS\assembly\{Name}\{Version}\ + /// - Cached at: %APPDATA%\Catswords\assembly\{Name}\{Version}\ /// - BaseUrl must be set by Main() before calling Register() /// public static class AssemblyLoader @@ -30,12 +31,12 @@ namespace WelsonJS.Launcher /// Must be set before Register() or LoadNativeModules(). /// public static string BaseUrl { get; set; } = null; - public static ICompatibleLogger Logger { get; set; } = null; + public static string LoaderNamespace { get; set; } = typeof(AssemblyLoader).Namespace; + public static string AppName { get; set; } = "Catswords"; private static readonly object SyncRoot = new object(); private static bool _registered; - private static readonly string LoaderNamespace = typeof(AssemblyLoader).Namespace ?? "WelsonJS.Launcher"; private static readonly HttpClientHandler LegacyHttpHandler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.None @@ -168,20 +169,20 @@ namespace WelsonJS.Launcher if (string.IsNullOrWhiteSpace(BaseUrl)) { - Logger?.Error("AssemblyLoader.Register() called but BaseUrl is not set."); + Trace.TraceError("AssemblyLoader.Register() called but BaseUrl is not set."); throw new InvalidOperationException("AssemblyLoader.BaseUrl must be configured before Register()."); } if (!BaseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { - Logger?.Error("AssemblyLoader.BaseUrl must use HTTPS for security."); + Trace.TraceError("AssemblyLoader.BaseUrl must use HTTPS for security."); throw new InvalidOperationException("AssemblyLoader.BaseUrl must use HTTPS."); } AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; _registered = true; - Logger?.Info("AssemblyLoader: AssemblyResolve handler registered."); + Trace.TraceInformation("AssemblyLoader: AssemblyResolve handler registered."); } } @@ -203,17 +204,17 @@ namespace WelsonJS.Launcher lock (SyncRoot) { string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - string cacheDir = Path.Combine(appData, "WelsonJS", "assembly", ownerAssemblyName, versionString); + string cacheDir = Path.Combine(appData, AppName, "assembly", ownerAssemblyName, versionString); Directory.CreateDirectory(cacheDir); try { if (!SetDllDirectory(cacheDir)) - Logger?.Warn("SetDllDirectory failed for: {0}", cacheDir); + Trace.TraceWarning("SetDllDirectory failed for: {0}", cacheDir); } catch (Exception ex) { - Logger?.Warn("SetDllDirectory threw exception: {0}", ex.Message); + Trace.TraceWarning("SetDllDirectory threw exception: {0}", ex.Message); } foreach (string raw in fileNames) @@ -228,11 +229,11 @@ namespace WelsonJS.Launcher { string url = $"{BaseUrl.TrimEnd('/')}/native/{ownerAssemblyName}/{versionString}/{fileName}"; DownloadFile(url, localPath); - Logger?.Info("Downloaded native module: {0}", fileName); + Trace.TraceInformation("Downloaded native module: {0}", fileName); } else { - Logger?.Info("Using cached native module: {0}", localPath); + Trace.TraceInformation("Using cached native module: {0}", localPath); } EnsureSignedFileOrThrow(localPath, fileName); @@ -241,12 +242,12 @@ namespace WelsonJS.Launcher if (h == IntPtr.Zero) { int errorCode = Marshal.GetLastWin32Error(); - Logger?.Error("LoadLibrary failed for {0} with error code {1}", localPath, errorCode); + Trace.TraceError("LoadLibrary failed for {0} with error code {1}", localPath, errorCode); throw new InvalidOperationException($"Failed to load native module: {fileName} (error: {errorCode})"); } else { - Logger?.Info("Loaded native module: {0}", fileName); + Trace.TraceInformation("Loaded native module: {0}", fileName); } } } @@ -277,7 +278,7 @@ namespace WelsonJS.Launcher private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) { - Logger?.Info("AssemblyResolve: {0}", args.Name); + Trace.TraceInformation("AssemblyResolve: {0}", args.Name); AssemblyName req = new AssemblyName(args.Name); string simpleName = req.Name; @@ -290,7 +291,7 @@ namespace WelsonJS.Launcher var entryName = entry.GetName().Name; if (string.Equals(simpleName, entryName, StringComparison.OrdinalIgnoreCase)) { - Logger?.Info("AssemblyResolve: skipping entry assembly {0}", simpleName); + Trace.TraceInformation("AssemblyResolve: skipping entry assembly {0}", simpleName); return null; } } @@ -301,7 +302,7 @@ namespace WelsonJS.Launcher lock (SyncRoot) { string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - string cacheDir = Path.Combine(appData, "WelsonJS", "assembly", simpleName, versionStr); + string cacheDir = Path.Combine(appData, AppName, "assembly", simpleName, versionStr); string dllPath = Path.Combine(cacheDir, simpleName + ".dll"); Directory.CreateDirectory(cacheDir); @@ -310,16 +311,16 @@ namespace WelsonJS.Launcher { string url = $"{BaseUrl.TrimEnd('/')}/managed/{simpleName}/{versionStr}/{simpleName}.dll"; DownloadFile(url, dllPath); - Logger?.Info("Downloaded managed assembly: {0}", simpleName); + Trace.TraceInformation("Downloaded managed assembly: {0}", simpleName); } else { - Logger?.Info("Using cached managed assembly: {0}", dllPath); + Trace.TraceInformation("Using cached managed assembly: {0}", dllPath); } if (!File.Exists(dllPath)) { - Logger?.Warn("AssemblyResolve: managed assembly not found after download attempt: {0}", simpleName); + Trace.TraceWarning("AssemblyResolve: managed assembly not found after download attempt: {0}", simpleName); return null; } @@ -345,13 +346,13 @@ namespace WelsonJS.Launcher if (isDll && TryDownloadCompressedFile(gzUrl, dest)) { - Logger?.Info("Downloaded and decompressed file to: {0}", dest); + Trace.TraceInformation("Downloaded and decompressed file to: {0}", dest); downloaded = true; } if (!downloaded) { - Logger?.Info("Downloading file from: {0}", url); + Trace.TraceInformation("Downloading file from: {0}", url); res = Http.GetAsync(url).GetAwaiter().GetResult(); res.EnsureSuccessStatusCode(); @@ -361,7 +362,7 @@ namespace WelsonJS.Launcher s.CopyTo(fs); } - Logger?.Info("Downloaded file to: {0}", dest); + Trace.TraceInformation("Downloaded file to: {0}", dest); } if (!File.Exists(dest)) @@ -371,12 +372,12 @@ namespace WelsonJS.Launcher } catch (HttpRequestException ex) { - Logger?.Error("Network or I/O error downloading {0}: {1}", url, ex.Message); + Trace.TraceError("Network or I/O error downloading {0}: {1}", url, ex.Message); throw; } catch (Exception ex) { - Logger?.Error("Unexpected error downloading {0}: {1}", url, ex.Message); + Trace.TraceError("Unexpected error downloading {0}: {1}", url, ex.Message); throw; } finally @@ -396,7 +397,7 @@ namespace WelsonJS.Launcher { if (res.StatusCode == HttpStatusCode.NotFound) { - Logger?.Info("No gzipped variant at {0}; falling back to uncompressed URL.", gzUrl); + Trace.TraceInformation("No gzipped variant at {0}; falling back to uncompressed URL.", gzUrl); return false; } @@ -419,12 +420,12 @@ namespace WelsonJS.Launcher } catch (HttpRequestException ex) { - Logger?.Warn("Network or I/O error downloading compressed file from {0}: {1}", gzUrl, ex.Message); + Trace.TraceWarning("Network or I/O error downloading compressed file from {0}: {1}", gzUrl, ex.Message); throw; } catch (Exception ex) { - Logger?.Error("Unexpected error downloading compressed file from {0}: {1}", gzUrl, ex.Message); + Trace.TraceError("Unexpected error downloading compressed file from {0}: {1}", gzUrl, ex.Message); throw; } finally @@ -437,7 +438,7 @@ namespace WelsonJS.Launcher } catch (Exception ex) { - Logger?.Info("Failed to delete temporary file {0}: {1}", tempFile, ex.Message); + Trace.TraceInformation("Failed to delete temporary file {0}: {1}", tempFile, ex.Message); } } } @@ -461,7 +462,7 @@ namespace WelsonJS.Launcher { if (!File.Exists(path)) { - Logger?.Error("File does not exist for signature verification: {0}", logicalName); + Trace.TraceError("File does not exist for signature verification: {0}", logicalName); throw new FileNotFoundException("File not found for signature verification: " + logicalName, path); } @@ -469,17 +470,17 @@ namespace WelsonJS.Launcher if (status == FileSignatureStatus.Valid) { - Logger?.Info("Signature OK: {0}", logicalName); + Trace.TraceInformation("Signature OK: {0}", logicalName); return; } if (status == FileSignatureStatus.NoSignature) { - Logger?.Error("BLOCKED unsigned binary: {0}", logicalName); + Trace.TraceError("BLOCKED unsigned binary: {0}", logicalName); throw new InvalidOperationException("Unsigned binary blocked: " + logicalName); } - Logger?.Error("BLOCKED invalid signature: {0}", logicalName); + Trace.TraceError("BLOCKED invalid signature: {0}", logicalName); throw new InvalidOperationException("Invalid signature: " + logicalName); } diff --git a/WelsonJS.Toolkit/Catswords.Phantomizer/Catswords.Phantomizer.csproj b/WelsonJS.Toolkit/Catswords.Phantomizer/Catswords.Phantomizer.csproj new file mode 100644 index 0000000..7f5a53b --- /dev/null +++ b/WelsonJS.Toolkit/Catswords.Phantomizer/Catswords.Phantomizer.csproj @@ -0,0 +1,15 @@ +๏ปฟ + + + netstandard2.0 + Catswords Research + Namhyeon Go, 2025 Catswords OSS and WelsonJS Contributors + https://github.com/gnh1201/welsonjs + git + https://github.com/gnh1201/welsonjs + loader + Catswords.Phantomizer is an HTTP-based dynamic-link library (DLL) loader designed for .NET applications. It allows your application to fetch and load assemblies directly from your CDN (Azure Blob, S3, Cloudflare R2, etc.) at runtime, with optional GZip compression support. + Namhyeon Go, 2025 Catswords OSS and WelsonJS Contributors + + + diff --git a/WelsonJS.Toolkit/Catswords.Phantomizer/LICENSE b/WelsonJS.Toolkit/Catswords.Phantomizer/LICENSE new file mode 100644 index 0000000..f144743 --- /dev/null +++ b/WelsonJS.Toolkit/Catswords.Phantomizer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Namhyeon Go , 2025 Catswords OSS and WelsonJS Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/WelsonJS.Toolkit/Catswords.Phantomizer/README.md b/WelsonJS.Toolkit/Catswords.Phantomizer/README.md new file mode 100644 index 0000000..0b223d7 --- /dev/null +++ b/WelsonJS.Toolkit/Catswords.Phantomizer/README.md @@ -0,0 +1,117 @@ +# Catswords.Phantomizer + +**Catswords.Phantomizer** is an HTTP-based dynamic-link library (DLL) loader designed for .NET applications. +It allows your application to fetch and load assemblies directly from your CDN (Azure Blob, S3, Cloudflare R2, etc.) at runtime, with optional GZip compression support. + +--- + +## ๐Ÿš€ Features + +* Load managed (`*.dll`) and native (`*.dll`) assemblies over HTTP +* Optional `.dll.gz` decompression for faster network delivery +* CDN-friendly URL structure +* Easy bootstrap through a small embedded loader +* Loader is implemented using **pure .NET BCL only**, ensuring stable operation without external dependencies +* Built-in **code-signing verification** support to ensure assemblies are trusted and tamper-free + +--- + +## ๐Ÿ“ฆ How to Use + +### 1. Embed Phantomizer into your project + +Add `Catswords.Phantomizer.dll.gz` to your `Resources.resx` file. + +--- + +### 2. Initialize Phantomizer at application startup + +Place the following code inside your `Main` method, static constructor, or any early entry point: + +```csharp +static Program() { + // ... + InitializeAssemblyLoader(); + // ... +} + +private static void InitializeAssemblyLoader() +{ + byte[] gzBytes = Properties.Resources.Phantomizer; + + byte[] dllBytes; + using (var input = new MemoryStream(gzBytes)) + using (var gz = new GZipStream(input, CompressionMode.Decompress)) + using (var output = new MemoryStream()) + { + gz.CopyTo(output); + dllBytes = output.ToArray(); + } + + Assembly phantomAsm = Assembly.Load(dllBytes); + Type loaderType = phantomAsm.GetType("Catswords.Phantomizer.AssemblyLoader", true); + + loaderType.GetProperty("BaseUrl")?.SetValue(null, GetAppConfig("AssemblyBaseUrl")); // Set your CDN base URL + loaderType.GetProperty("LoaderNamespace")?.SetValue(null, typeof(Program).Namespace); + loaderType.GetProperty("AppName")?.SetValue(null, "WelsonJS"); // Set your application name + loaderType.GetMethod("Register")?.Invoke(null, null); + + var loadNativeModulesMethod = loaderType.GetMethod( + "LoadNativeModules", + BindingFlags.Public | BindingFlags.Static, + binder: null, + types: new[] { typeof(string), typeof(Version), typeof(string[]) }, + modifiers: null + ); + + if (loadNativeModulesMethod == null) + throw new InvalidOperationException("LoadNativeModules(string, Version, string[]) method not found."); + + loadNativeModulesMethod.Invoke(null, new object[] + { + "ChakraCore", + new Version(1, 13, 0, 0), + new[] { "ChakraCore.dll" } + }); +} +``` + +--- + +### 3. Upload your DLL files to a CDN + +Upload your managed and native assemblies to your CDN following the URL pattern below. + +#### ๐Ÿ“ URL Rules + +| Type | Example URL | Description | +| ------------------ | ----------------------------------------------------------------------------------- | ------------------------------- | +| Managed DLL | `https://example.cdn.tld/packages/managed/MyManagedLib/1.0.0.0/MyManagedLib.dll` | Normal .NET assembly | +| Managed DLL (GZip) | `https://example.cdn.tld/packages/managed/MyManagedLib/1.0.0.0/MyManagedLib.dll.gz` | GZip-compressed .NET assembly | +| Native DLL | `https://example.cdn.tld/packages/native/MyNativeLib/1.0.0.0/MyNativeLib.dll` | Native assembly | +| Native DLL (GZip) | `https://example.cdn.tld/packages/native/MyNativeLib/1.0.0.0/MyNativeLib.dll.gz` | GZip-compressed native assembly | + +--- + +### 4. ๐ŸŽ‰ Start loading assemblies over HTTP + +Once Phantomizer is initialized, your application will automatically fetch missing assemblies from your CDN. + +--- + +## Download the pre-compiled file +* [Download Catswords.Phantomizer.dll.gz (catswords.blob.core.windows.net)](https://catswords.blob.core.windows.net/welsonjs/packages/managed/Catswords.Phantomizer/1.0.0.0/Catswords.Phantomizer.dll.gz) + +--- + +## Report abuse +* [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security) +* [abuse@catswords.re.kr](mailto:abuse@catswords.re.kr) + +## Join the community +I am always open. Collaboration, opportunities, and community activities are all welcome. + +* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss) +* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join) +* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI) +* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj) diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs index bfac5b5..965117a 100644 --- a/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs +++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs @@ -8,7 +8,9 @@ using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.IO; +using System.IO.Compression; using System.Linq; +using System.Reflection; using System.Threading; using System.Windows.Forms; using WelsonJS.Launcher.Telemetry; @@ -33,10 +35,7 @@ namespace WelsonJS.Launcher _logger = new TraceLogger(); // load external assemblies - AssemblyLoader.BaseUrl = GetAppConfig("AssemblyBaseUrl"); - AssemblyLoader.Logger = _logger; - AssemblyLoader.Register(); - AssemblyLoader.LoadNativeModules("ChakraCore", new Version(1, 13, 0, 0), new[] { "ChakraCore.dll" }); + InitializeAssemblyLoader(); // telemetry try @@ -114,6 +113,49 @@ namespace WelsonJS.Launcher _mutex.Dispose(); } + private static void InitializeAssemblyLoader() + { + byte[] gzBytes = Properties.Resources.Phantomizer; + + byte[] dllBytes; + using (var input = new MemoryStream(gzBytes)) + using (var gz = new GZipStream(input, CompressionMode.Decompress)) + using (var output = new MemoryStream()) + { + gz.CopyTo(output); + dllBytes = output.ToArray(); + } + + Assembly phantomAsm = Assembly.Load(dllBytes); + Type loaderType = phantomAsm.GetType("Catswords.Phantomizer.AssemblyLoader", true); + + loaderType.GetProperty("BaseUrl")?.SetValue(null, GetAppConfig("AssemblyBaseUrl")); + loaderType.GetProperty("LoaderNamespace")?.SetValue(null, typeof(Program).Namespace); + loaderType.GetProperty("AppName")?.SetValue(null, "WelsonJS"); + loaderType.GetMethod("Register")?.Invoke(null, null); + + var loadNativeModulesMethod = loaderType.GetMethod( + "LoadNativeModules", + BindingFlags.Public | BindingFlags.Static, + binder: null, + types: new[] { typeof(string), typeof(Version), typeof(string[]) }, + modifiers: null + ); + + if (loadNativeModulesMethod == null) + { + throw new InvalidOperationException("LoadNativeModules(string, Version, string[]) method not found."); + } + + loadNativeModulesMethod.Invoke(null, new object[] + { + "ChakraCore", + new Version(1, 13, 0, 0), + new[] { "ChakraCore.dll" } + }); + } + + public static void RecordFirstDeployTime(string directory, string instanceId) { // get current time diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs index b5f61ae..095137a 100644 --- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs +++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs @@ -342,6 +342,16 @@ namespace WelsonJS.Launcher.Properties { } } + /// + /// System.Byte[] ํ˜•์‹์˜ ์ง€์—ญํ™”๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. + /// + internal static byte[] Phantomizer { + get { + object obj = ResourceManager.GetObject("Phantomizer", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// https://github.com/gnh1201/welsonjs๊ณผ(์™€) ์œ ์‚ฌํ•œ ์ง€์—ญํ™”๋œ ๋ฌธ์ž์—ด์„ ์ฐพ์Šต๋‹ˆ๋‹ค. /// diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx index d5d208a..5bc52ea 100644 --- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx +++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx @@ -241,4 +241,7 @@ https://catswords.blob.core.windows.net/welsonjs/packages + + ..\Resources\Catswords.Phantomizer.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Resources/Catswords.Phantomizer.dll.gz b/WelsonJS.Toolkit/WelsonJS.Launcher/Resources/Catswords.Phantomizer.dll.gz new file mode 100644 index 0000000..57569a7 Binary files /dev/null and b/WelsonJS.Toolkit/WelsonJS.Launcher/Resources/Catswords.Phantomizer.dll.gz differ diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj b/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj index a1a876a..b2ae16d 100644 --- a/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj +++ b/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj @@ -88,7 +88,6 @@ - @@ -171,6 +170,7 @@ + diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit.sln b/WelsonJS.Toolkit/WelsonJS.Toolkit.sln index 38c0f9a..74d1463 100644 --- a/WelsonJS.Toolkit/WelsonJS.Toolkit.sln +++ b/WelsonJS.Toolkit/WelsonJS.Toolkit.sln @@ -17,6 +17,8 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "WelsonJS.Cryptography", "We EndProject Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "WelsonJS.Cryptography.Test", "WelsonJS.Cryptography.Test\WelsonJS.Cryptography.Test.vbproj", "{C65EC34B-71C7-47CF-912E-D304283EB412}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Catswords.Phantomizer", "Catswords.Phantomizer\Catswords.Phantomizer.csproj", "{59C67003-C14E-4703-927F-318BFF15F903}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -81,6 +83,14 @@ Global {C65EC34B-71C7-47CF-912E-D304283EB412}.Release|Any CPU.Build.0 = Release|Any CPU {C65EC34B-71C7-47CF-912E-D304283EB412}.Release|x86.ActiveCfg = Release|x86 {C65EC34B-71C7-47CF-912E-D304283EB412}.Release|x86.Build.0 = Release|x86 + {59C67003-C14E-4703-927F-318BFF15F903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Debug|x86.ActiveCfg = Debug|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Debug|x86.Build.0 = Debug|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Release|Any CPU.Build.0 = Release|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Release|x86.ActiveCfg = Release|Any CPU + {59C67003-C14E-4703-927F-318BFF15F903}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE