diff --git a/Source/Platforms/DotNet/System.Text.Encoding.CodePages.dll b/Source/Platforms/DotNet/System.Text.Encoding.CodePages.dll new file mode 100644 index 000000000..b874cda32 --- /dev/null +++ b/Source/Platforms/DotNet/System.Text.Encoding.CodePages.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:086cdd51afaa43b2bdc9db17585d988f8bf0df481b1974974422d6b4aa920eaa +size 740496 diff --git a/Source/Platforms/DotNet/System.Text.Encoding.CodePages.xml b/Source/Platforms/DotNet/System.Text.Encoding.CodePages.xml new file mode 100644 index 000000000..292222845 --- /dev/null +++ b/Source/Platforms/DotNet/System.Text.Encoding.CodePages.xml @@ -0,0 +1,29 @@ + + + + System.Text.Encoding.CodePages + + + + Provides access to an encoding provider for code pages that otherwise are available only in the desktop .NET Framework. + + + Returns the encoding associated with the specified code page identifier. + The code page identifier of the preferred encoding which the encoding provider may support. + The encoding associated with the specified code page identifier, or if the provider does not support the requested codepage encoding. + + + Returns the encoding associated with the specified code page name. + The code page name of the preferred encoding which the encoding provider may support. + The encoding associated with the specified code page, or if the provider does not support the requested encoding. + + + Returns an array that contains all the encodings that are supported by the . + An array that contains all the supported encodings. + + + Gets an encoding provider for code pages supported in the desktop .NET Framework but not in the current .NET Framework platform. + An encoding provider that allows access to encodings not supported on the current .NET Framework platform. + + + \ No newline at end of file diff --git a/Source/ThirdParty/nethost/LICENSE.TXT b/Source/ThirdParty/nethost/LICENSE.TXT index a616ed188..984713a49 100644 --- a/Source/ThirdParty/nethost/LICENSE.TXT +++ b/Source/ThirdParty/nethost/LICENSE.TXT @@ -20,4 +20,4 @@ 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 +SOFTWARE. diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs index 930c4933d..e15793e7f 100644 --- a/Source/ThirdParty/nethost/nethost.Build.cs +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -52,9 +52,6 @@ public class nethost : ThirdPartyModule break; case TargetPlatform.Linux: case TargetPlatform.Android: - case TargetPlatform.Switch: - case TargetPlatform.PS4: - case TargetPlatform.PS5: options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "libnethost.so")); break; @@ -62,6 +59,12 @@ public class nethost : ThirdPartyModule options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "libnethost.dylib")); break; + case TargetPlatform.Switch: + case TargetPlatform.PS4: + case TargetPlatform.PS5: + options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); + //options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libhostfxr.a")); + break; default: throw new InvalidPlatformException(options.Platform.Target); } diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index af7ac1b6b..e97bd3875 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -77,8 +77,7 @@ namespace Flax.Build case TargetArchitecture.ARM64: arch = "arm64"; break; - default: - throw new InvalidArchitectureException(architecture); + default: throw new InvalidArchitectureException(architecture); } switch (platform) { @@ -120,8 +119,7 @@ namespace Flax.Build dotnetPath = "/usr/local/share/dotnet/"; break; } - default: - throw new InvalidPlatformException(platform); + default: throw new InvalidPlatformException(platform); } // Pick SDK version @@ -171,7 +169,7 @@ namespace Flax.Build TryAddHostRuntime(TargetPlatform.Windows, TargetArchitecture.ARM64, "win-arm64"); TryAddHostRuntime(TargetPlatform.Mac, TargetArchitecture.x64, "osx-x64"); TryAddHostRuntime(TargetPlatform.Mac, TargetArchitecture.ARM64, "osx-arm64"); - + // Found IsValid = true; Log.Verbose($"Found .NET SDK {VersionName} (runtime {RuntimeVersionName}) at {RootPath}"); @@ -180,14 +178,26 @@ namespace Flax.Build } /// - /// Gets the path to runtime host contents folder for a given target platform and architecure. - /// In format: /packs/Microsoft.NETCore.App.Host.//runtimes/-/native + /// Gets the path to runtime host contents folder for a given target platform and architecture. + /// In format: <RootPath>/packs/Microsoft.NETCore.App.Host.<os>/<VersionName>/runtimes/<os>-<arch>/native /// public bool GetHostRuntime(TargetPlatform platform, TargetArchitecture arch, out string path) { return _hostRuntimes.TryGetValue(new KeyValuePair(platform, arch), out path); } + /// + /// Adds an external hostfx location for a given platform. + /// + /// Target platform. + /// Target architecture. + /// Folder path with contents. + public void AddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string path) + { + if (Directory.Exists(path)) + _hostRuntimes[new KeyValuePair(platform, arch)] = path; + } + private bool TryAddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string rid) { if (string.IsNullOrEmpty(rid)) diff --git a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs index b0f16186e..4474cbfc8 100644 --- a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs +++ b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs @@ -215,7 +215,7 @@ namespace Flax.Deploy throw new Exception(string.Format("Project {0} does not exist!", project)); } - string cmdLine = string.Format("\"{0}\" /m /t:Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", project, buildConfig, buildPlatform, Verbosity); + string cmdLine = string.Format("\"{0}\" /m /t:Restore,Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", project, buildConfig, buildPlatform, Verbosity); int result = Utilities.Run(msBuild, cmdLine); if (result != 0) { @@ -245,7 +245,7 @@ namespace Flax.Deploy throw new Exception(string.Format("Unable to build solution {0}. Solution file not found.", solutionFile)); } - string cmdLine = string.Format("\"{0}\" /m /t:Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", solutionFile, buildConfig, buildPlatform, Verbosity); + string cmdLine = string.Format("\"{0}\" /m /t:Restore,Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", solutionFile, buildConfig, buildPlatform, Verbosity); if (props != null) { foreach (var e in props) diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/NewtonsoftJson.cs b/Source/Tools/Flax.Build/Deps/Dependencies/NewtonsoftJson.cs index c0e8fe086..0d8b2ec02 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/NewtonsoftJson.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/NewtonsoftJson.cs @@ -75,7 +75,7 @@ namespace Flax.Deps.Dependencies } // AOT build (disabled codegen) - Utilities.ReplaceInFile(Path.Combine(root, "Src", "Newtonsoft.Json", "Newtonsoft.Json.csproj"), "HAVE_RUNTIME_SERIALIZATION;", ";"); + Utilities.ReplaceInFile(Path.Combine(root, "Src", "Newtonsoft.Json", "Newtonsoft.Json.csproj"), "HAVE_REFLECTION_EMIT;", ";"); Deploy.VCEnvironment.BuildSolution(solutionPath, configuration, buildPlatform); foreach (var platform in options.Platforms) { diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs b/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs index 0883dbef4..5c2bc938d 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs @@ -212,39 +212,8 @@ namespace Flax.Deps.Dependencies { case TargetPlatform.Windows: { - msBuild = VCEnvironment.MSBuildPath; - - // Some consoles don't support the latest Visual Studio 2022 - var vsVersion = VisualStudioVersion.VisualStudio2022; - switch (targetPlatform) - { - case TargetPlatform.PS4: - vsVersion = VisualStudioVersion.VisualStudio2017; - break; - case TargetPlatform.PS5: - case TargetPlatform.Switch: - vsVersion = VisualStudioVersion.VisualStudio2019; - break; - } - if (vsVersion != VisualStudioVersion.VisualStudio2022) - { - // TODO: override VS version in cmake_generate_projects.py too - var visualStudioInstances = VisualStudioInstance.GetInstances(); - foreach (var visualStudioInstance in visualStudioInstances) - { - if (visualStudioInstance.Version <= vsVersion) - { - var toolPath = Path.Combine(visualStudioInstance.Path, "MSBuild\\Current\\Bin\\MSBuild.exe"); - if (!File.Exists(toolPath)) - toolPath = Path.Combine(visualStudioInstance.Path, "MSBuild\\15.0\\Bin\\MSBuild.exe"); - if (File.Exists(toolPath)) - { - msBuild = toolPath; - break; - } - } - } - } + GetMsBuildForPlatform(targetPlatform, out var vsVersion, out msBuild); + // TODO: override VS version in cmake_generate_projects.py too if (File.Exists(msBuild)) { envVars.Add("PATH", Path.GetDirectoryName(msBuild)); diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs new file mode 100644 index 000000000..11533852c --- /dev/null +++ b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs @@ -0,0 +1,244 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Flax.Build; +using Flax.Deploy; +using Ionic.Zip; + +namespace Flax.Deps.Dependencies +{ + /// + /// .NET runtime + /// + /// + class nethost : Dependency + { + /// + public override TargetPlatform[] Platforms + { + get + { + switch (BuildPlatform) + { + case TargetPlatform.Windows: + return new[] + { + TargetPlatform.PS4, + }; + default: return new TargetPlatform[0]; + } + } + } + + private string root; + + private void Build(BuildOptions options, TargetPlatform targetPlatform, TargetArchitecture architecture) + { + // Build configuration (see build.cmd -help) + string configuration = "Release"; + string framework = "net7.0"; + + // Clean output directory + var artifacts = Path.Combine(root, "artifacts"); + SetupDirectory(artifacts, true); + + // Peek options + string os, arch, runtimeFlavor, subset, hostRuntimeName, buildArgsBase = string.Empty; + bool setupVersion = false; + string[] hostRuntimeFiles = Array.Empty(); + var envVars = new Dictionary(); + switch (architecture) + { + case TargetArchitecture.x86: + arch = "x86"; + break; + case TargetArchitecture.x64: + arch = "x64"; + break; + case TargetArchitecture.ARM: + arch = "arm"; + break; + case TargetArchitecture.ARM64: + arch = "arm64"; + break; + default: throw new InvalidArchitectureException(architecture); + } + switch (targetPlatform) + { + case TargetPlatform.Windows: + os = "windows"; + runtimeFlavor = "CoreCLR"; + subset = "clr"; + hostRuntimeName = $"win-{arch}"; + break; + case TargetPlatform.Linux: + os = "Linux"; + runtimeFlavor = "CoreCLR"; + subset = "clr"; + hostRuntimeName = $"linux-{arch}"; + break; + case TargetPlatform.Mac: + os = "OSX"; + runtimeFlavor = "CoreCLR"; + subset = "clr"; + hostRuntimeName = $"osx-{arch}"; + break; + case TargetPlatform.Android: + os = "Android"; + runtimeFlavor = "Mono"; + subset = "mono+libs"; + hostRuntimeName = $"android-{arch}"; + break; + case TargetPlatform.PS4: + os = "PS4"; + runtimeFlavor = "Mono"; + subset = "mono+libs"; + setupVersion = true; + buildArgsBase = " /p:RuntimeOS=ps4 -cmakeargs \"-DCLR_CROSS_COMPONENTS_BUILD=1\""; + hostRuntimeName = $"ps4-{arch}"; + hostRuntimeFiles = new[] + { + "coreclr_delegates.h", + "hostfxr.h", + "nethost.h", + "libnethost.a", + }; + break; + default: throw new InvalidPlatformException(targetPlatform); + } + + // Setup build environment variables for build system + string buildScript = null; + switch (BuildPlatform) + { + case TargetPlatform.Windows: + { + buildScript = "build.cmd"; + if (setupVersion) + { + // Setup _version.c file manually + SetupDirectory(Path.Combine(artifacts, "obj"), false); + foreach (var file in new[] { "_version.c", "_version.h" }) + File.Copy(Path.Combine(root, "eng", "native", "version", file), Path.Combine(artifacts, "obj", file), true); + } + var msBuild = VCEnvironment.MSBuildPath; + if (File.Exists(msBuild)) + { + envVars.Add("PATH", Path.GetDirectoryName(msBuild)); + } + break; + } + case TargetPlatform.Linux: + { + buildScript = "build.sh"; + break; + } + case TargetPlatform.Mac: + { + buildScript = "build.sh"; + break; + } + default: throw new InvalidPlatformException(BuildPlatform); + } + + // Print the runtime version + string version; + { + var doc = new XmlDocument(); + doc.Load(Path.Combine(root, "eng", "Versions.props")); + version = doc["Project"]["PropertyGroup"]["ProductVersion"].InnerText; + Log.Info("Building dotnet/runtime version " + version); + } + + // Build + buildArgsBase = $"-os {os} -a {arch} -f {framework} -c {configuration} -lc {configuration} -rc {configuration} -rf {runtimeFlavor}{buildArgsBase}"; + foreach (var buildStep in new[] { subset, "host.pkg", "packs.product" }) + { + var buildArgs = $"{buildArgsBase} {buildStep}"; + if (BuildPlatform == TargetPlatform.Windows) + { + // For some reason running from Visual Studio fails the build so use command shell + //buildArgs = $"/C {buildScript} {buildArgs}"; + //buildApp = "cmd.exe"; + // TODO: maybe write command line into bat file and run it here? + WinAPI.SetClipboard($"{buildScript} {buildArgs}"); + WinAPI.MessageBox.Show($"Open console command in folder '{root}' and run command from clipboard. Then close this dialog.", "Run command manually", WinAPI.MessageBox.Buttons.Ok); + } + else + { + Utilities.Run(Path.Combine(root, buildScript), buildArgs, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars); + } + } + + // Deploy build products + var dstBinaries = GetThirdPartyFolder(options, targetPlatform, architecture); + var srcHostRuntime = Path.Combine(artifacts, "bin", $"{hostRuntimeName}.{configuration}", "corehost"); + foreach (var file in hostRuntimeFiles) + { + Utilities.FileCopy(Path.Combine(srcHostRuntime, file), Path.Combine(dstBinaries, file)); + } + var dstDotnet = Path.Combine(dstBinaries, "Dotnet"); + var dstClassLibrary = Path.Combine(dstDotnet, "shared", "Microsoft.NETCore.App", version); + SetupDirectory(dstClassLibrary, true); + foreach (var file in new[] + { + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + }) + { + Utilities.FileCopy(Path.Combine(root, file), Path.Combine(dstDotnet, file)); + } + var srcDotnetLibsPkg = Path.Combine(artifacts, "packages", "Release", "Shipping", $"Microsoft.NETCore.App.Runtime.Mono.{hostRuntimeName}.{version}.nupkg"); + if (!File.Exists(srcDotnetLibsPkg)) + throw new Exception($"Missing .NET Core App class library package at '{srcDotnetLibsPkg}'"); + var srcDotnetLibsPkgTemp = srcDotnetLibsPkg + "Temp"; + using (var zip = new ZipFile(srcDotnetLibsPkg)) + { + zip.ExtractAll(srcDotnetLibsPkgTemp, ExtractExistingFileAction.OverwriteSilently); + } + var privateCorelib = "System.Private.CoreLib.dll"; + Utilities.FileCopy(Path.Combine(srcDotnetLibsPkgTemp, "runtimes", hostRuntimeName, "native", privateCorelib), Path.Combine(dstClassLibrary, privateCorelib)); + Utilities.DirectoryCopy(Path.Combine(srcDotnetLibsPkgTemp, "runtimes", hostRuntimeName, "lib", "net7.0"), dstClassLibrary, false, true); + Utilities.DirectoriesDelete(srcDotnetLibsPkgTemp); + // TODO: host/fxr//hostfxr.dll + // TODO: shared/Microsoft.NETCore.App//hostpolicy.dl + // TODO: shared/Microsoft.NETCore.App//System.IO.Compression.Native.dll + } + + /// + public override void Build(BuildOptions options) + { + root = options.IntermediateFolder; + + // Ensure to have dependencies installed + Utilities.Run("ninja", "--version", null, null, Utilities.RunOptions.ThrowExceptionOnError); + Utilities.Run("cmake", "--version", null, null, Utilities.RunOptions.ThrowExceptionOnError); + + // Get the source + CloneGitRepo(root, "https://github.com/FlaxEngine/dotnet-runtime.git", "flax-master", null, true); + SetupDirectory(Path.Combine(root, "src", "external"), false); + + foreach (var platform in options.Platforms) + { + var platformData = Path.Combine(GetBinariesFolder(options, platform), "Data", "nethost"); + if (Directory.Exists(platformData)) + Utilities.DirectoryCopy(platformData, root, true, true); + switch (platform) + { + case TargetPlatform.PS4: + { + Build(options, platform, TargetArchitecture.x64); + break; + } + } + } + + // Copy license + var dstIncludePath = Path.Combine(options.ThirdPartyFolder, "nethost"); + Utilities.FileCopy(Path.Combine(root, "LICENSE.TXT"), Path.Combine(dstIncludePath, "LICENSE.TXT")); + } + } +} diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index 625430738..3b7f0bd9e 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.IO; using Flax.Build; using Flax.Build.Platforms; +using Flax.Build.Projects.VisualStudio; +using Flax.Deploy; namespace Flax.Deps { @@ -118,13 +120,16 @@ namespace Flax.Deps /// The remote url. /// The commit to checkout. /// The custom arguments to add to the clone command. - public static void CloneGitRepo(string path, string url, string commit = null, string args = null) + /// True if initialize submodules of the repository (recursive). + public static void CloneGitRepo(string path, string url, string commit = null, string args = null, bool submodules = false) { if (!Directory.Exists(Path.Combine(path, Path.GetFileNameWithoutExtension(url), ".git"))) { string cmdLine = string.Format("clone \"{0}\" \"{1}\"", url, path); if (args != null) cmdLine += " " + args; + if (submodules) + cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); } @@ -141,13 +146,16 @@ namespace Flax.Deps /// The local path for close. /// The remote url. /// The custom arguments to add to the clone command. - public static void CloneGitRepoFast(string path, string url, string args = null) + /// True if initialize submodules of the repository (recursive). + public static void CloneGitRepoFast(string path, string url, string args = null, bool submodules = false) { if (!Directory.Exists(Path.Combine(path, Path.GetFileNameWithoutExtension(url), ".git"))) { string cmdLine = string.Format("clone \"{0}\" \"{1}\" --depth 1", url, path); if (args != null) cmdLine += " " + args; + if (submodules) + cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); } @@ -161,7 +169,8 @@ namespace Flax.Deps /// The name of the branch to checkout. /// The commit to checkout. /// The custom arguments to add to the clone command. - public static void CloneGitRepoSingleBranch(string path, string url, string branch, string commit = null, string args = null) + /// True if initialize submodules of the repository (recursive). + public static void CloneGitRepoSingleBranch(string path, string url, string branch, string commit = null, string args = null, bool submodules = false) { if (!Directory.Exists(Path.Combine(path, ".git"))) { @@ -170,6 +179,8 @@ namespace Flax.Deps cmdLine += " --depth 1"; if (args != null) cmdLine += " " + args; + if (submodules) + cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); } @@ -187,11 +198,14 @@ namespace Flax.Deps /// The name of the branch to checkout. /// The commit to checkout. /// The custom arguments to add to the clone command. - public static void GitCheckout(string path, string branch, string commit = null, string args = null) + /// True if initialize submodules of the repository (recursive). + public static void GitCheckout(string path, string branch, string commit = null, string args = null, bool submodules = false) { string cmdLine = string.Format("checkout -B {0} origin/{0}", branch); if (args != null) cmdLine += " " + args; + if (submodules) + cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, path, Utilities.RunOptions.None); @@ -384,5 +398,42 @@ namespace Flax.Deps } Utilities.Run(path, args, null, workspace, Utilities.RunOptions.ThrowExceptionOnError, envVars); } + + internal bool GetMsBuildForPlatform(TargetPlatform targetPlatform, out VisualStudioVersion vsVersion, out string msBuildPath) + { + // Some consoles don't support the latest Visual Studio 2022 + vsVersion = VisualStudioVersion.VisualStudio2022; + switch (targetPlatform) + { + case TargetPlatform.PS4: + vsVersion = VisualStudioVersion.VisualStudio2017; + break; + case TargetPlatform.PS5: + case TargetPlatform.Switch: + vsVersion = VisualStudioVersion.VisualStudio2019; + break; + } + if (vsVersion != VisualStudioVersion.VisualStudio2022) + { + var visualStudioInstances = VisualStudioInstance.GetInstances(); + foreach (var visualStudioInstance in visualStudioInstances) + { + if (visualStudioInstance.Version <= vsVersion) + { + var toolPath = Path.Combine(visualStudioInstance.Path, "MSBuild\\Current\\Bin\\MSBuild.exe"); + if (!File.Exists(toolPath)) + toolPath = Path.Combine(visualStudioInstance.Path, "MSBuild\\15.0\\Bin\\MSBuild.exe"); + if (File.Exists(toolPath)) + { + vsVersion = visualStudioInstance.Version; + msBuildPath = toolPath; + return true; + } + } + } + } + msBuildPath = VCEnvironment.MSBuildPath; + return false; + } } } diff --git a/Source/Tools/Flax.Build/Deps/DepsBuilder.cs b/Source/Tools/Flax.Build/Deps/DepsBuilder.cs index a225f9404..31b62d260 100644 --- a/Source/Tools/Flax.Build/Deps/DepsBuilder.cs +++ b/Source/Tools/Flax.Build/Deps/DepsBuilder.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Linq; +using System.Text; using Flax.Build; namespace Flax.Deps @@ -21,6 +22,9 @@ namespace Flax.Deps public static bool Run() { + // Fix error 'IBM437' is not a supported encoding name from Ionic.Zip.ZipFile + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + // Setup var buildPlatform = Platform.BuildPlatform; var options = new Dependency.BuildOptions diff --git a/Source/Tools/Flax.Build/Flax.Build.csproj b/Source/Tools/Flax.Build/Flax.Build.csproj index c9d152d27..626b81502 100644 --- a/Source/Tools/Flax.Build/Flax.Build.csproj +++ b/Source/Tools/Flax.Build/Flax.Build.csproj @@ -38,6 +38,9 @@ ..\..\..\Source\Platforms\DotNet\Ionic.Zip.Reduced.dll + + ..\..\..\Source\Platforms\DotNet\System.Text.Encoding.CodePages.dll + ..\..\..\Source\Platforms\DotNet\Newtonsoft.Json.dll diff --git a/Source/Tools/Flax.Build/Utilities/WinAPI.cs b/Source/Tools/Flax.Build/Utilities/WinAPI.cs index f684745b2..ae0c5a5fb 100644 --- a/Source/Tools/Flax.Build/Utilities/WinAPI.cs +++ b/Source/Tools/Flax.Build/Utilities/WinAPI.cs @@ -26,5 +26,148 @@ namespace Flax.Build public delegate bool SymEnumerateSymbolsProc64(string SymbolName, ulong SymbolAddress, uint SymbolSize, IntPtr UserContext); } + + public static class kernel32 + { + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr GlobalLock(IntPtr hMem); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GlobalUnlock(IntPtr hMem); + } + + public static class user32 + { + [DllImport("user32.dll")] + public static extern bool EmptyClipboard(); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenClipboard(IntPtr hWndNewOwner); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseClipboard(); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data); + + [DllImport("user32.dll")] + public static extern int MessageBoxA(IntPtr hWnd, string lpText, string lpCaption, uint uType); + } + + // https://github.com/CopyText/TextCopy/blob/main/src/TextCopy/WindowsClipboard.cs + public static void SetClipboard(string text) + { + user32.OpenClipboard(IntPtr.Zero); + user32.EmptyClipboard(); + IntPtr hGlobal = default; + try + { + var bytes = (text.Length + 1) * 2; + hGlobal = Marshal.AllocHGlobal(bytes); + var target = kernel32.GlobalLock(hGlobal); + try + { + Marshal.Copy(text.ToCharArray(), 0, target, text.Length); + } + finally + { + kernel32.GlobalUnlock(target); + } + user32.SetClipboardData(13, hGlobal); + hGlobal = default; + } + finally + { + if (hGlobal != default) + { + Marshal.FreeHGlobal(hGlobal); + } + user32.CloseClipboard(); + } + } + + // https://gist.github.com/nathan130200/53dec19cdcd895281fb568ec63e1275b + public static class MessageBox + { + public enum Buttons + { + AbortRetryIgnore = 0x00000002, + CancelTryIgnore = 0x00000006, + Help = 0x00004000, + Ok = 0x00000000, + OkCancel = 0x00000001, + RetryCancel = 0x00000005, + YesNo = 0x00000004, + YesNoCancel = 0x00000003, + } + + public enum Result + { + Abort = 3, + Cancel = 2, + Continue = 11, + Ignore = 5, + No = 7, + Ok = 1, + Retry = 10, + Yes = 6, + } + + public enum DefaultButton : uint + { + Button1 = 0x00000000, + Button2 = 0x00000100, + Button3 = 0x00000200, + Button4 = 0x00000300, + } + + public enum Modal : uint + { + Application = 0x00000000, + System = 0x00001000, + Task = 0x00002000 + } + + public enum Icon : uint + { + Warning = 0x00000030, + Information = 0x00000040, + Question = 0x00000020, + Error = 0x00000010 + } + + public static Result Show(string text) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, "\0", (uint)Buttons.Ok); + } + + public static Result Show(string text, string caption) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, caption, (uint)Buttons.Ok); + } + + public static Result Show(string text, string caption, Buttons buttons) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, caption, (uint)buttons); + } + + public static Result Show(string text, string caption, Buttons buttons, Icon icon) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon)); + } + + public static Result Show(string text, string caption, Buttons buttons, Icon icon, DefaultButton button) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button)); + } + + public static Result Show(string text, string caption, Buttons buttons, Icon icon, DefaultButton button, Modal modal) + { + return (Result)user32.MessageBoxA(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button) | ((uint)modal)); + } + } } }