using IronPython.Hosting; using Microsoft.CSharp.RuntimeBinder; using Microsoft.Scripting.Hosting; using Microsoft.Scripting.Runtime; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Security.Principal; using System.Text; using System.Threading.Tasks; namespace cforge { /// /// Misc helper classes for all kinds of stuff /// class Helper { #region Registry /// /// Function to check if URL Handler for cforge tool is installed /// /// true, if yes. false, if not public static bool CheckRegistryProtocol() { RegistryKey cforge = Registry.ClassesRoot.OpenSubKey("cforge"); if (cforge == null) { return false; } return true; } public static void RegisterProtocol(bool bVerbose) { try { String fullpath = GetCFORGEAssemblyPath(); RegistryKey cforgekey = Registry.ClassesRoot.OpenSubKey("cforge"); cforgekey = Registry.ClassesRoot.CreateSubKey("cforge", true); cforgekey.SetValue("", "URL:cforge Protocol"); cforgekey.SetValue("URL Protocol", ""); RegistryKey cforgeshell = cforgekey.CreateSubKey("shell"); RegistryKey shellopen = cforgeshell.CreateSubKey("open"); RegistryKey opencommand = shellopen.CreateSubKey("command"); opencommand.SetValue("", "\"" + fullpath + "\" \"%1\""); Console.WriteLine("[INFO] Installed URL Handler for cforge tool. \r\n\tPath is: " + fullpath); } catch (Exception ex) { Console.WriteLine("Exception while adding the registry key. Perhaps you are not admin?"); Console.WriteLine(ex.ToString()); } } internal static void ShowLicenseInfo() { Console.WriteLine("License information "); Console.WriteLine(""); Console.Write(Resources.license); Console.WriteLine(""); } #endregion #region SystemPath public static void AddToSystemPath(bool bVerbose) { string strPath = System.Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); string[] split = strPath.Split(new Char[] { ';' }); string path = Path.GetDirectoryName(GetCFORGEAssemblyPath()); string strNewSystemPath = strPath + ";" + path; if (!split.Contains(path)) { System.Environment.SetEnvironmentVariable("Path", strNewSystemPath, EnvironmentVariableTarget.Machine); } } public static void bootstrap(bool bVerbose) { /// bootstrapper /// warning for svn.exe if not present string exepath = Helper.FindExePath("svn.exe"); if (exepath == String.Empty) { Console.WriteLine("[WARNING] Please install Turtoise SVN with command line client option!"); } else { Console.WriteLine("[INFO] Turtoise SVN detected. \r\n\tPath is: " + exepath); exepath = String.Empty; } /// add libdoc.exe to path to enable CODESYS libdocscripting (TODO expand this section) exepath = Helper.FindExePath("libdoc.exe"); string strPath = System.Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); string path = String.Empty; string strNewSystemPath = String.Empty; if (exepath == String.Empty) { /// add path to: "C:\Program Files\CODESYS 3.5.14.0\CODESYS\DocScripting\3.5.14.0" /// for now quick and dirty => should become dynamic path = "C:\\Program Files\\CODESYS 3.5.14.0\\CODESYS\\DocScripting\\3.5.14.0"; strNewSystemPath = strPath + ";" + path; System.Environment.SetEnvironmentVariable("Path", strNewSystemPath, EnvironmentVariableTarget.Machine); Console.WriteLine("[INFO] Environmentvariable for DocScripting added: \r\n\tPath is: " + path); } else { Console.WriteLine("[INFO] DocScripting detected. \r\n\tPath is: " + exepath); exepath = String.Empty; } } /// /// Expands environment variables and, if unqualified, locates the exe in the working directory /// or the evironment's path. /// /// The name of the executable file /// The fully-qualified path to the file /// Raised when the exe was not found public static string FindExePath(string exe) { exe = Environment.ExpandEnvironmentVariables(exe); if (!File.Exists(exe)) { if (Path.GetDirectoryName(exe) == String.Empty) { foreach (string test in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(';')) { string path = test.Trim(); if (!String.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exe))) return Path.GetFullPath(path); } } return String.Empty; /// throw new FileNotFoundException(new FileNotFoundException().Message, exe); } return Path.GetFullPath(exe); } #endregion public static bool EasyAttachEnabled() { try { String path = GetCFORGEAssemblyPath(); String Debugfile = Path.Combine(Path.GetDirectoryName(path), "debug"); if (File.Exists(Debugfile)) return true; } catch { } return false; } /// /// Function to retrieve the location of the currenty assembly (cforge.exe). /// This should be located in the CODESYS installation subfolder "CFORGE" /// /// full path to cforge.exe private static String GetCFORGEAssemblyPath() { String path = System.Reflection.Assembly.GetExecutingAssembly().Location; return path; } private static bool IsCODESYSPathInstallation() { String path = GetCFORGEAssemblyPath(); if (path.Contains("bin") && (path.Contains("Debug") || path.Contains("Release"))) return false; return true; } /// /// Function to retrieve the CODESYS AP_ROOT (this is where "Common" etc. folders are) /// /// full path to AP ROOT private static String GetCODESYSRoot() { if (IsCODESYSPathInstallation()) { // twice up from cforge.exe (if installed in CODESYS) String path = GetCFORGEAssemblyPath(); path = Directory.GetParent(path).FullName; return Directory.GetParent(path).FullName; } // for now return a normal installation path for CODESYS return @"C:\Program Files (x86)\3S CODESYS\CODESYS\"; } /// /// Function to retrieve the "ScriptLib" Path inside CODESYS. We just take the last one, probably this is the newest one /// /// full path to ScriptLib version folder private static String GetCODESYSScriptingLibPath() { String path = Path.Combine(GetCODESYSRoot(), "ScriptLib"); String version = Directory.EnumerateDirectories(path).Last(); path = Path.Combine(path, version); return path; } /// /// Function to retrieve the CFORGE Script path (this is where the IronPython scripts should reside) /// /// full path to CFORGE Scripts private static String GetCFORGEScriptPath() { if (IsCODESYSPathInstallation()) { // \CFORGE\Scripts String path = GetCODESYSRoot(); return Path.Combine(path, "CFORGE", "Scripts"); } String localscriptpath = System.AppDomain.CurrentDomain.BaseDirectory; localscriptpath = Directory.GetParent(localscriptpath).FullName; localscriptpath = Directory.GetParent(localscriptpath).FullName; localscriptpath = Directory.GetParent(localscriptpath).FullName; return Path.Combine(localscriptpath,"Package", "CFORGE", "Scripts"); } /// /// Function to enumerate all IronPython scripts to exend cforge.exe inside Scripts folder /// /// List of IPY scripts public static List GetAllScripts() { List liScripts = new List(); try { String path = GetCFORGEScriptPath(); foreach (String file in Directory.EnumerateFiles(path)) { if (Path.GetExtension(file).ToLowerInvariant() == ".py") { String shortfilename = Path.GetFileNameWithoutExtension(file); liScripts.Add(shortfilename); } } } catch(Exception e) { Console.WriteLine("[EXCEPTION] GetAllScripts: " + e.Message); } return liScripts; } public static bool IsUserElevated() { using (var curIdent = WindowsIdentity.GetCurrent()) { var principal = new WindowsPrincipal(curIdent); return principal.IsInRole(WindowsBuiltInRole.Administrator); } } public static void RunElevated(String args) { String strAssemblyPath = GetCFORGEAssemblyPath(); try { Process p = new Process(); p.StartInfo.FileName = strAssemblyPath; p.StartInfo.Arguments = args; p.StartInfo.Verb = "runas"; p.Start(); p.WaitForExit(); } catch(Exception ex) { Console.WriteLine("[EXCEPTION] RunElevated: " + ex.Message); } } #region Scripting public static void ExecuteIPyScript(String command, String[] args, bool bVerbose) { String scriptfile = Path.Combine(GetCFORGEScriptPath(), command + ".py"); Console.WriteLine(); Console.WriteLine("[INFO] Executing: " + scriptfile); Console.WriteLine(); if (!File.Exists(scriptfile)) { Console.WriteLine(); Console.WriteLine("[ERROR] Cannot execute command: no such file or directory: " + scriptfile); Console.WriteLine(); return; } //ScriptEngine engine = Python.CreateEngine(); ScriptEngine engine = IronPython.Hosting.Python.CreateEngine(new Dictionary { { "Debug", ScriptingRuntimeHelpers.True } }); Debug.Assert(engine.Runtime.Setup.DebugMode); String strScriptingPath = GetCODESYSScriptingLibPath(); try { dynamic sys = Python.GetSysModule(engine); sys.argv[0] = scriptfile; foreach (string arg in args) { sys.argv.Add(arg); } sys.path.Add(GetCFORGEScriptPath()); sys.path.Add(strScriptingPath); var source = engine.CreateScriptSourceFromFile(scriptfile); source.Execute(); //Console.WriteLine("Script finished"); } catch (IronPython.Runtime.Exceptions.SystemExitException ex) { Console.WriteLine(); Console.WriteLine("[INFO] command " + command + ".py exited: "); ExceptionOperations eo = engine.GetService(); string error = "[INFO] " + eo.FormatException(ex); Console.WriteLine(error); } catch (Exception ex) { Console.WriteLine(); Console.WriteLine("[Exception] command " + command + ".py caused an exception: " ); ExceptionOperations eo = engine.GetService(); string error = eo.FormatException(ex); Console.WriteLine(error); } } public static void ShowUsageIPyScript(string command, bool v) { String scriptfile = Path.Combine(GetCFORGEScriptPath(), command + ".py"); if (!File.Exists(scriptfile)) { Console.WriteLine("[ERROR] Cannot execute command: no such file or directory: " + scriptfile); return; } ScriptRuntime runtime; runtime = Python.CreateRuntime(); Python.GetEngine(runtime); try { dynamic script = runtime.UseFile(scriptfile); var help = script.cforge_usage(); foreach (var item in help) { String cmd = "--" + command + " " + item[0].ToString(); cmd = cmd.PadRight(32) + item[1]; Console.WriteLine(cmd); } } catch { // we silently ignore errors in this script, as we only want to show the usage! //Console.WriteLine(("--" + command).PadRight(32) + ""); } } #endregion } }