Skip to content
Permalink
Browse files

Use exe wrapper on Windows

There was a bug with the old batch->powershell->java wrapper when it
came to quoted arguments. To fix this became a rabbit hole, and it ended
up being easier to just revist the C# wrapper. This removes the
ClickOnce installation, so this is just a simple wrapper executable.
Still need to revisit the installation mechanisms later to re-add double
click support in windows, but for the time being this is good enough as
a replacement in cmdline.
  • Loading branch information...
LadyCailin committed Oct 2, 2019
1 parent 7350575 commit a77ca4b998817f2791b40df389b36adf10a0a7d4
@@ -3,130 +3,175 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;

namespace mscript {
class Program {
static void Main(string[] args) {
try {
if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun) {
Console.WriteLine("Finishing installation...");
SetAddRemoveProgramsIcon();
Console.WriteLine("Installation complete. Press enter to exit.");
Console.ReadLine();
return;
}
} catch(System.Deployment.Application.InvalidDeploymentException e) {
// Being run directly from the executable, so this is not the first installed run anyways.
}
class Program {
static void Main(string[] args) {
//try {
// if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun) {
// Console.WriteLine("Finishing installation...");
// SetAddRemoveProgramsIcon();
// Console.WriteLine("Installation complete. Press enter to exit.");
// Console.ReadLine();
// return;
// }
//} catch(System.Deployment.Application.InvalidDeploymentException e) {
// // Being run directly from the executable, so this is not the first installed run anyways.
//}

string[] activationData = null;
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null) {
activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
}
string startFile = null;
if (activationData != null) {
// We were launched directly if this is null, otherwise
// activationData[0] has the name of the file we were launched from
startFile = activationData[0];
}
string[] activationData = null;
if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null) {
activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
}
string startFile = null;
if (activationData != null) {
// We were launched directly if this is null, otherwise
// activationData[0] has the name of the file we were launched from
startFile = activationData[0];
}

string jarLocation = Registry.CurrentUser.OpenSubKey("Software\\MethodScript").GetValue("JarLocation").ToString();
string jarLocation = Registry.CurrentUser.OpenSubKey("Software\\MethodScript").GetValue("JarLocation").ToString();
List<string> modulesArgs = new List<string>();
// Pull out the modules and add them here if java > 8
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "java.exe";
start.RedirectStandardOutput = true;
start.UseShellExecute = false;
List<string> a = new List<string>();
a.Add("-jar");
a.Add(jarLocation);
a.Add("java-version");
start.Arguments = JoinAndEscape(a);
string strOutput;
using(Process p = Process.Start(start)) {
strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
int javaVersion = int.Parse(strOutput);
if(javaVersion > 7) {
ZipArchive zipFile = ZipFile.OpenRead(jarLocation);
ZipArchiveEntry file = zipFile.Entries.Where((ZipArchiveEntry e) => {
return e.FullName.Equals("interpreter-helpers/modules");
}).Single();
Stream stream = file.Open();
StreamReader reader = new StreamReader(stream);
string modules = reader.ReadToEnd();
modules = modules.Replace("\r", "");
foreach(string module in modules.Split('\n')) {
if(module.Equals(string.Empty)) {
continue;
}
modulesArgs.Add("--add-opens");
modulesArgs.Add(module + "=ALL-UNNAMED");
}
}
}

List<string> command = new List<string>();
if (startFile == null) {
// start interpreter
command.Add("-jar");
command.Add(jarLocation);
command.Add("interpreter");
// Don't think these are needed here
//command.Add("--location-----");
//command.Add(AppDomain.CurrentDomain.BaseDirectory);
} else {
// launched from a *.ms file
if(args.Length > 0 && args[0] == "--") {
// Script passthrough to java -jar CH.jar <arguments>
command.Add("-jar");
command.Add(jarLocation);
command.AddRange(args);
} else if (System.Environment.GetEnvironmentVariable("DEBUG_MSCRIPT") != null && System.Environment.GetEnvironmentVariable("DEBUG_MSCRIPT") == "1") {
// java debug mode
command.Add("-Xrs");
command.Add("-Xdebug");
command.Add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9001");
command.Add("-jar");
command.Add(jarLocation);
command.Add("cmdline");
command.Add(startFile);
command.AddRange(args);
} else {
// Normal launch with script
command.Add("-Xrs");
command.Add("-jar");
command.Add(jarLocation);
command.Add("cmdline");
command.Add(startFile);
command.AddRange(args);
}
}
List<string> command = new List<string>();
if(System.Environment.GetEnvironmentVariable("DEBUG_MSCRIPT") != null && System.Environment.GetEnvironmentVariable("DEBUG_MSCRIPT") == "1") {
// java debug mode
command.Add("-Xrs");
command.Add("-Xdebug");
command.Add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9001");
}
command.AddRange(modulesArgs);
if(args.Length == 0) {
// start interpreter
command.Add("-jar");
command.Add(jarLocation);
command.Add("interpreter");
// Don't think these are needed here
//command.Add("--location-----");
//command.Add(AppDomain.CurrentDomain.BaseDirectory);
} else {
// launched from a *.ms file
if(args.Length > 0 && args[0] == "--") {
// Script passthrough to java -jar CH.jar <arguments>
command.Add("-jar");
command.Add(jarLocation);
// Remove the -- from the args
for(int i = 1; i < args.Length; i++) {
command.Add(args[i]);
}
} else {
// Normal launch with script
command.Add("-jar");
command.Add(jarLocation);
command.Add("cmdline");
command.Add(startFile);
command.AddRange(args);
}
}

{
ProcessStartInfo start = new ProcessStartInfo();
start.UseShellExecute = false;
start.Arguments = JoinAndEscape(command);
#if DEBUG
Console.WriteLine("Command is: " + start.Arguments);
#endif
start.FileName = "java.exe";
start.UseShellExecute = false;

ProcessStartInfo start = new ProcessStartInfo();
start.Arguments = JoinAndEscape(command);
start.FileName = "java.exe";
start.UseShellExecute = false;
//Console.WriteLine(start.Arguments);

//Console.WriteLine(start.Arguments);
int exitCode;

int exitCode;
using(Process proc = Process.Start(start)) {
proc.WaitForExit();
exitCode = proc.ExitCode;
}
}

using (Process proc = Process.Start(start)) {
proc.WaitForExit();
exitCode = proc.ExitCode;
}
//Console.WriteLine("command: " + string.Join(" ", command));
//Console.ReadLine();
return;
}

//Console.WriteLine("command: " + string.Join(" ", command));
//Console.ReadLine();
return;
}
private static string JoinAndEscape(List<string> args) {
string s = "";
foreach(string arg in args) {
if(arg == null) {
continue;
}
string arg2 = arg.Replace("\\", "\\\\");
arg2 = arg2.Replace("\"", "\\\"");
arg2 = "\"" + arg2 + "\"";
s += arg2;
s += " ";
}
return s;
}

private static string JoinAndEscape(List<string> args) {
string s = "";
foreach(string arg in args) {
string arg2 = arg.Replace("\\", "\\\\");
arg2 = arg2.Replace("\"", "\\\"");
arg2 = "\"" + arg2 + "\"";
s += arg2;
s += " ";
}
return s;
}
//private static void SetAddRemoveProgramsIcon() {
// try {
// string assemblyDescription = "MethodScript";

// //the icon is included in this program
// string iconSourcePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "commandhelper_icon.ico");
// //Console.WriteLine("iconSourcePath: " + iconSourcePath);
// //Console.WriteLine("assemblyDescription: " + assemblyDescription);

private static void SetAddRemoveProgramsIcon() {
try {
string assemblyDescription = "MethodScript";

//the icon is included in this program
string iconSourcePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "commandhelper_icon.ico");
//Console.WriteLine("iconSourcePath: " + iconSourcePath);
//Console.WriteLine("assemblyDescription: " + assemblyDescription);
// if (!File.Exists(iconSourcePath))
// return;

if (!File.Exists(iconSourcePath))
return;

RegistryKey myUninstallKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
string[] mySubKeyNames = myUninstallKey.GetSubKeyNames();
for (int i = 0; i < mySubKeyNames.Length; i++) {
RegistryKey myKey = myUninstallKey.OpenSubKey(mySubKeyNames[i], true);
object myValue = myKey.GetValue("DisplayName");
if (myValue != null && myValue.ToString() == assemblyDescription) {
//Console.WriteLine("Setting iconSourcePath in " + myKey.Name);
myKey.SetValue("DisplayIcon", iconSourcePath);
break;
}
}
} catch (Exception ex) {
//log an error
}
}
}
// RegistryKey myUninstallKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
// string[] mySubKeyNames = myUninstallKey.GetSubKeyNames();
// for (int i = 0; i < mySubKeyNames.Length; i++) {
// RegistryKey myKey = myUninstallKey.OpenSubKey(mySubKeyNames[i], true);
// object myValue = myKey.GetValue("DisplayName");
// if (myValue != null && myValue.ToString() == assemblyDescription) {
// //Console.WriteLine("Setting iconSourcePath in " + myKey.Name);
// myKey.SetValue("DisplayIcon", iconSourcePath);
// break;
// }
// }
// } catch(Exception) {
// //log an error
// }
//}
}
}
@@ -38,19 +38,22 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\target\csharp\Debug\</OutputPath>
<OutputPath>..\target\csharp\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\target\csharp\Release\</OutputPath>
<OutputPath>..\target\csharp\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>8316999540B038BC3D016377F0522994E7CE72C9</ManifestCertificateThumbprint>
@@ -63,15 +66,37 @@
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
<SignManifests>false</SignManifests>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>commandhelper_icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\target\csharp\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\target\csharp\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>portable</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Deployment" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Management" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -1,20 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
# Visual Studio Version 16
VisualStudioVersion = 16.0.29020.237
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mscript", "mscript.csproj", "{8BC476C5-E566-4BFD-A86C-2EE0C813676F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Debug|x64.ActiveCfg = Debug|x64
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Debug|x64.Build.0 = Debug|x64
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Release|Any CPU.Build.0 = Release|Any CPU
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Release|x64.ActiveCfg = Release|x64
{8BC476C5-E566-4BFD-A86C-2EE0C813676F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -7,6 +7,8 @@
import java.util.List;
import java.util.Objects;

// TODO: Add enum type to arg types, as well as providing hooks for autocomplete and custom argument validators

/**
* An ArgumentParser allows for programmatic registration of arguments, which
* will be automatically parsed and validated. Additionally, automatically

0 comments on commit a77ca4b

Please sign in to comment.
You can’t perform that action at this time.