diff --git a/DotNetToJScript/DotNetToJScript.csproj b/DotNetToJScript/DotNetToJScript.csproj
index 79f2009..bc38768 100644
--- a/DotNetToJScript/DotNetToJScript.csproj
+++ b/DotNetToJScript/DotNetToJScript.csproj
@@ -44,8 +44,11 @@
+
+
+
diff --git a/DotNetToJScript/IScriptGenerator.cs b/DotNetToJScript/IScriptGenerator.cs
new file mode 100644
index 0000000..8812a71
--- /dev/null
+++ b/DotNetToJScript/IScriptGenerator.cs
@@ -0,0 +1,38 @@
+// This file is part of DotNetToJScript - A tool to generate a
+// JScript which bootstraps an arbitrary v2.NET Assembly and class.
+// Copyright (C) James Forshaw 2017
+//
+// DotNetToJScript is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// DotNetToJScript is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with DotNetToJScript. If not, see .
+
+namespace DotNetToJScript
+{
+ enum RuntimeVersion
+ {
+ None,
+ v2,
+ v4,
+ Auto,
+ }
+
+ interface IScriptGenerator
+ {
+ string GenerateScript(byte[] serialized_object,
+ string entry_class_name,
+ string additional_script,
+ RuntimeVersion version,
+ bool enable_debug);
+ bool SupportsScriptlet { get; }
+ string ScriptName { get; }
+ }
+}
diff --git a/DotNetToJScript/JScriptGenerator.cs b/DotNetToJScript/JScriptGenerator.cs
new file mode 100644
index 0000000..da15d5d
--- /dev/null
+++ b/DotNetToJScript/JScriptGenerator.cs
@@ -0,0 +1,127 @@
+// This file is part of DotNetToJScript - A tool to generate a
+// JScript which bootstraps an arbitrary v2.NET Assembly and class.
+// Copyright (C) James Forshaw 2017
+//
+// DotNetToJScript is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// DotNetToJScript is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with DotNetToJScript. If not, see .
+
+using System;
+using System.Text;
+
+namespace DotNetToJScript
+{
+ class JScriptGenerator : IScriptGenerator
+ {
+ static string jscript_template =
+ @"var serialized_obj = [
+%SERIALIZED%
+];
+var entry_class = '%CLASS%';
+
+try {
+ setversion();
+ var stm = new ActiveXObject('System.IO.MemoryStream');
+ var fmt = new ActiveXObject('System.Runtime.Serialization.Formatters.Binary.BinaryFormatter');
+ var al = new ActiveXObject('System.Collections.ArrayList')
+
+ for (i in serialized_obj) {
+ stm.WriteByte(serialized_obj[i]);
+ }
+
+ stm.Position = 0;
+ var n = fmt.SurrogateSelector;
+ var d = fmt.Deserialize_2(stm);
+ al.Add(n);
+ var o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class);
+ %ADDEDSCRIPT%
+} catch (e) {
+ debug(e.message);
+}";
+
+ static string version_detection = @"function setversion() {
+ var shell = new ActiveXObject('WScript.Shell');
+ ver = 'v4.0.30319';
+ try {
+ shell.RegRead('HKLM\\SOFTWARE\\Microsoft\\.NETFramework\\v4.0.30319\\');
+ } catch(e) {
+ ver = 'v2.0.50727';
+ }
+ shell.Environment('Process')('COMPLUS_Version') = ver;
+}";
+ static string version_v2 = @"function setversion() {
+ new ActiveXObject('WScript.Shell').Environment('Process')('COMPLUS_Version') = 'v2.0.50727';
+}";
+ static string version_v4 = @"function setversion() {
+ new ActiveXObject('WScript.Shell').Environment('Process')('COMPLUS_Version') = 'v4.0.30319';
+}";
+ static string version_none = @"function setversion() {}";
+
+ static string debug_enabled = @"function debug(s) { WScript.Echo(s); }" + Environment.NewLine;
+ static string debug_disabled = @"function debug(s) { }" + Environment.NewLine;
+
+ static string GetSetVersionJScript(RuntimeVersion version)
+ {
+ string script = version_none;
+ switch (version)
+ {
+ case RuntimeVersion.Auto:
+ script = version_detection;
+ break;
+ case RuntimeVersion.v2:
+ script = version_v2;
+ break;
+ case RuntimeVersion.v4:
+ script = version_v4;
+ break;
+ }
+ return script + Environment.NewLine;
+ }
+
+
+ public string ScriptName
+ {
+ get
+ {
+ return "JScript";
+ }
+ }
+
+ public bool SupportsScriptlet
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public string GenerateScript(byte[] serialized_object, string entry_class_name, string additional_script, RuntimeVersion version, bool enable_debug)
+ {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < serialized_object.Length; ++i)
+ {
+ builder.Append(serialized_object[i]);
+ if (i < serialized_object.Length - 1)
+ {
+ builder.Append(",");
+ }
+ if (i > 0 && (i % 32) == 0)
+ {
+ builder.AppendLine();
+ }
+ }
+
+ return (enable_debug ? debug_enabled : debug_disabled) + GetSetVersionJScript(version)
+ + jscript_template.Replace("%SERIALIZED%", builder.ToString()).Replace("%CLASS%", entry_class_name).Replace("%ADDEDSCRIPT%", additional_script);
+ }
+ }
+}
diff --git a/DotNetToJScript/Program.cs b/DotNetToJScript/Program.cs
index db85cc3..12db6bd 100644
--- a/DotNetToJScript/Program.cs
+++ b/DotNetToJScript/Program.cs
@@ -27,78 +27,10 @@ using System.Text;
using System.Xml;
using System.Xml.Schema;
-namespace Serialize
+namespace DotNetToJScript
{
class Program
{
- static string jscript_template =
- @"
-var serialized_obj = [
-%SERIALIZED%
-];
-var entry_class = '%CLASS%';
-
-try {
- var stm = new ActiveXObject('System.IO.MemoryStream');
- var fmt = new ActiveXObject('System.Runtime.Serialization.Formatters.Binary.BinaryFormatter');
- var al = new ActiveXObject('System.Collections.ArrayList')
-
- for (i in serialized_obj) {
- stm.WriteByte(serialized_obj[i]);
- }
-
- stm.Position = 0;
- var n = fmt.SurrogateSelector;
- var d = fmt.Deserialize_2(stm);
- al.Add(n);
- var o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class);
- %ADDEDSCRIPT%
-} catch (e) {
- WScript.Echo(e.message);
-}";
-
- static string vba_template =
- @"
-Private Function decodeHex(hex)
- On Error Resume Next
- Dim DM, EL
- Set DM = CreateObject(""Microsoft.XMLDOM"")
- Set EL = DM.createElement(""tmp"")
- EL.DataType = ""bin.hex""
- EL.Text = hex
- decodeHex = EL.NodeTypedValue
-End Function
-
-Function Run()
- Dim serialized_obj
- %SERIALIZED%
-
- entry_class = ""%CLASS%""
-
- Dim stm As Object, fmt As Object, al As Object
- Set stm = CreateObject(""System.IO.MemoryStream"")
- Set fmt = CreateObject(""System.Runtime.Serialization.Formatters.Binary.BinaryFormatter"")
- Set al = CreateObject(""System.Collections.ArrayList"")
-
- Dim dec
- dec = decodeHex(serialized_obj)
-
- For Each i In dec
- stm.WriteByte i
- Next i
-
- stm.Position = 0
-
- Dim n As Object, d As Object, o As Object
- Set n = fmt.SurrogateSelector
- Set d = fmt.Deserialize_2(stm)
- al.Add n
-
- Set o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class)
- %ADDEDSCRIPT%
-End Function
-";
-
static string scriptlet_template =
@"
@@ -112,6 +44,11 @@ End Function
";
+ enum ScriptLanguage
+ {
+ JScript,
+ VBA,
+ }
static object BuildLoaderDelegate(byte[] assembly)
{
@@ -151,7 +88,7 @@ End Function
const string DEFAULT_ENTRY_CLASS_NAME = "TestClass";
- static string CreateScriptlet(string script, bool register_script)
+ static string CreateScriptlet(string script, string script_name, bool register_script)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(scriptlet_template);
@@ -162,7 +99,7 @@ End Function
XmlNode root_node = doc.SelectSingleNode(register_script ? "/package/component/registration" : "/package/component");
XmlNode script_node = root_node.AppendChild(doc.CreateElement("script"));
- script_node.Attributes.Append(doc.CreateAttribute("language")).Value = "JScript";
+ script_node.Attributes.Append(doc.CreateAttribute("language")).Value = script_name;
script_node.AppendChild(doc.CreateCDataSection(script));
using (MemoryStream stm = new MemoryStream())
@@ -204,6 +141,16 @@ End Function
{
WriteError(String.Format(format, args));
}
+
+ static string GetEnumString(Type enum_type)
+ {
+ return String.Join(", ", Enum.GetNames(enum_type));
+ }
+
+ static void ParseEnum(string name, out T value) where T : struct
+ {
+ value = (T)Enum.Parse(typeof(T), name, true);
+ }
static void Main(string[] args)
{
@@ -211,17 +158,19 @@ End Function
{
if (Environment.Version.Major != 2)
{
- WriteError("This tool only works on v2 of the CLR");
+ WriteError("This tool should only be run on v2 of the CLR");
Environment.Exit(1);
}
string output_file = null;
string entry_class_name = DEFAULT_ENTRY_CLASS_NAME;
- string script_file = null;
+ string additional_script = String.Empty;
bool mscorlib_only = false;
bool scriptlet_moniker = false;
bool scriptlet_uninstall = false;
- bool vba_code = false;
+ bool enable_debug = false;
+ RuntimeVersion version = RuntimeVersion.None;
+ ScriptLanguage language = ScriptLanguage.JScript;
bool show_help = false;
@@ -229,10 +178,15 @@ End Function
{ "n", "Build a script which only uses mscorlib.", v => mscorlib_only = v != null },
{ "m", "Build a scriptlet file in moniker format.", v => scriptlet_moniker = v != null },
{ "u", "Build a scriptlet file in uninstall format.", v => scriptlet_uninstall = v != null },
- { "v", "Build a VBA file.", v => vba_code = v != null },
+ { "d", "Enable debug output from script", v => enable_debug = v != null },
+ { "l|lang=", String.Format("Specify script language to use ({0})",
+ GetEnumString(typeof(ScriptLanguage))), v => ParseEnum(v, out language) },
+ { "v", "Build a VBA file (use -lang switch).", v => language = ScriptLanguage.VBA },
+ { "ver=", String.Format("Specify .NET version to use ({0})",
+ GetEnumString(typeof(RuntimeVersion))), v => ParseEnum(v, out version) },
{ "o=", "Specify output file (default is stdout).", v => output_file = v },
{ "c=", String.Format("Specify entry class name (default {0})", entry_class_name), v => entry_class_name = v },
- { "s=", "Specify file with additional script. 'o' is created instance.", v => script_file = v },
+ { "s=", "Specify file with additional script. 'o' is created instance.", v => additional_script = File.ReadAllText(v) },
{ "h|help", "Show this message and exit", v => show_help = v != null },
};
@@ -246,10 +200,17 @@ End Function
Environment.Exit(1);
}
- if (vba_code && (scriptlet_moniker || scriptlet_uninstall))
+ IScriptGenerator generator;
+ switch (language)
{
- WriteError("Cannot use '-v' in combination with scriptlet options.");
- Environment.Exit(1);
+ case ScriptLanguage.JScript:
+ generator = new JScriptGenerator();
+ break;
+ case ScriptLanguage.VBA:
+ generator = new VBAGenerator();
+ break;
+ default:
+ throw new ArgumentException("Invalid script language option");
}
byte[] assembly = File.ReadAllBytes(assembly_path);
@@ -284,54 +245,14 @@ End Function
MemoryStream stm = new MemoryStream();
fmt.Serialize(stm, mscorlib_only ? BuildLoaderDelegateMscorlib(assembly) : BuildLoaderDelegate(assembly));
- byte[] ba = stm.ToArray();
- string template;
- StringBuilder builder = new StringBuilder();
-
- if (vba_code)
- {
- template = vba_template;
-
- string hex_encoded = BitConverter.ToString(ba).Replace("-", "");
-
- for (int i = 0; i < hex_encoded.Length; i++)
- {
- if (i == 0)
- {
- builder.Append(" serialized_obj = \"");
- }
- else if (i % 100 == 0)
- {
- builder.Append("\"");
- builder.AppendLine();
- builder.Append(" serialized_obj = serialized_obj & \"");
- }
- builder.Append(hex_encoded[i]);
- }
- builder.Append("\"");
-
- } else {
- template = jscript_template;
-
- for (int i = 0; i < ba.Length; ++i)
- {
- builder.Append(ba[i]);
- if (i < ba.Length - 1)
- {
- builder.Append(",");
- }
- if (i > 0 && (i % 32) == 0)
- {
- builder.AppendLine();
- }
- }
- }
-
- string script = template.Replace("%SERIALIZED%", builder.ToString()).Replace("%CLASS%", entry_class_name).Replace("%ADDEDSCRIPT%", File.Exists(script_file) ? File.ReadAllText(script_file) : "");
-
+ string script = generator.GenerateScript(stm.ToArray(), entry_class_name, additional_script, version, enable_debug);
if (scriptlet_moniker || scriptlet_uninstall)
{
- script = CreateScriptlet(script, scriptlet_uninstall);
+ if (generator.SupportsScriptlet)
+ {
+ throw new ArgumentException(String.Format("{0} generator does not support Scriptlet output", generator.ScriptName));
+ }
+ script = CreateScriptlet(script, generator.ScriptName, scriptlet_uninstall);
}
if (!String.IsNullOrEmpty(output_file))
diff --git a/DotNetToJScript/VBAGenerator.cs b/DotNetToJScript/VBAGenerator.cs
new file mode 100644
index 0000000..9977d6d
--- /dev/null
+++ b/DotNetToJScript/VBAGenerator.cs
@@ -0,0 +1,112 @@
+// This file is part of DotNetToJScript - A tool to generate a
+// JScript which bootstraps an arbitrary v2.NET Assembly and class.
+// Copyright (C) James Forshaw 2017
+//
+// DotNetToJScript is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// DotNetToJScript is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with DotNetToJScript. If not, see .
+
+using System;
+using System.Text;
+
+namespace DotNetToJScript
+{
+ class VBAGenerator : IScriptGenerator
+ {
+ static string vba_template =
+ @"
+Private Function decodeHex(hex)
+ On Error Resume Next
+ Dim DM, EL
+ Set DM = CreateObject(""Microsoft.XMLDOM"")
+ Set EL = DM.createElement(""tmp"")
+ EL.DataType = ""bin.hex""
+ EL.Text = hex
+ decodeHex = EL.NodeTypedValue
+End Function
+
+Function Run()
+ Dim serialized_obj
+ %SERIALIZED%
+
+ entry_class = ""%CLASS%""
+
+ Dim stm As Object, fmt As Object, al As Object
+ Set stm = CreateObject(""System.IO.MemoryStream"")
+ Set fmt = CreateObject(""System.Runtime.Serialization.Formatters.Binary.BinaryFormatter"")
+ Set al = CreateObject(""System.Collections.ArrayList"")
+
+ Dim dec
+ dec = decodeHex(serialized_obj)
+
+ For Each i In dec
+ stm.WriteByte i
+ Next i
+
+ stm.Position = 0
+
+ Dim n As Object, d As Object, o As Object
+ Set n = fmt.SurrogateSelector
+ Set d = fmt.Deserialize_2(stm)
+ al.Add n
+
+ Set o = d.DynamicInvoke(al.ToArray()).CreateInstance(entry_class)
+ %ADDEDSCRIPT%
+End Function
+";
+
+ public string ScriptName
+ {
+ get
+ {
+ return "VBA";
+ }
+ }
+
+ public bool SupportsScriptlet
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public string GenerateScript(byte[] serialized_object, string entry_class_name, string additional_script, RuntimeVersion version, bool enable_debug)
+ {
+ if (version != RuntimeVersion.None)
+ {
+ throw new ArgumentException("VBA output does not support version detection");
+ }
+
+ string hex_encoded = BitConverter.ToString(serialized_object).Replace("-", "");
+ StringBuilder builder = new StringBuilder();
+
+ for (int i = 0; i < hex_encoded.Length; i++)
+ {
+ if (i == 0)
+ {
+ builder.Append(" serialized_obj = \"");
+ }
+ else if (i % 100 == 0)
+ {
+ builder.Append("\"");
+ builder.AppendLine();
+ builder.Append(" serialized_obj = serialized_obj & \"");
+ }
+ builder.Append(hex_encoded[i]);
+ }
+ builder.Append("\"");
+
+ return vba_template.Replace("%SERIALIZED%", builder.ToString()).Replace("%CLASS%", entry_class_name).Replace("%ADDEDSCRIPT%", additional_script);
+ }
+ }
+}
diff --git a/DotNetToJScript/app.config b/DotNetToJScript/app.config
new file mode 100644
index 0000000..2fa6e95
--- /dev/null
+++ b/DotNetToJScript/app.config
@@ -0,0 +1,3 @@
+
+
+
diff --git a/README b/README
index 0555433..680902b 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
This file is part of DotNetToJScript - A tool to generate a
-JScript which bootstraps an arbitrary v2.NET Assembly and class.
+JScript which bootstraps an arbitrary .NET Assembly and class.
Copyright (C) James Forshaw 2017
DotNetToJScript is free software: you can redistribute it and/or modify
@@ -18,11 +18,10 @@ along with DotNetToJScript. If not, see .
Usage Notes:
This only works from full trust JScript(obviously), so should work in
-scriptlets etc. It also only works if v2/v3/v3.5 is installed. If
-only v4+ is installed then the system will prompt for installation of
-.NET v2. Don't think there's any way around this, seems that while the
-COM objects are registered it doesn't fall-forward to using .NET 4 even
-though it should work in theory.
+scriptlets etc. By default it will only works if v2/v3/v3.5 is installed.
+However if you specify the '-ver auto' switch when building the output it
+will also work on v4+ only, however that will introduce a dependency on
+WScript.Shell which you might not want.
To use this you'll need to create an assembly which targets .NET 2 (though
in most cases you can also use 3.5 as you don't tend to see .NET 2 installed
@@ -59,7 +58,8 @@ o.DoSomething("SomeArg");
The default mode is to output a JScript file which can be executed in Windows
Scripting Host. However if you want a scriptlet pass either -m (for a scriptlet
which can be used from a scriptlet moniker) or -u (for a scriptlet which can be
-used from regsvr32).
+used from regsvr32). You can also specify the -v switch to output a VBA file which
+should work in Office Macros.
Finally by default the tool will output to stdout, you can output direct to a file
using the -o switch.
\ No newline at end of file