diff --git a/STPluginsExample/.ginignore b/STPluginsExample/.ginignore new file mode 100644 index 0000000..2e9693e --- /dev/null +++ b/STPluginsExample/.ginignore @@ -0,0 +1,2 @@ +obj +bin \ No newline at end of file diff --git a/STPluginsExample/.vscode/launch.json b/STPluginsExample/.vscode/launch.json new file mode 100644 index 0000000..cb85f30 --- /dev/null +++ b/STPluginsExample/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${env:SprutCAMDir}/sc.exe", + "args": [], + "cwd": "${workspaceFolder}", + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/STPluginsExample/.vscode/tasks.json b/STPluginsExample/.vscode/tasks.json new file mode 100644 index 0000000..a31cdb1 --- /dev/null +++ b/STPluginsExample/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/STPluginsExample.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/STPluginsExample.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/STPluginsExample.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/STPluginsExample/CAMPluginsFactory.cs b/STPluginsExample/CAMPluginsFactory.cs new file mode 100644 index 0000000..a4ebbec --- /dev/null +++ b/STPluginsExample/CAMPluginsFactory.cs @@ -0,0 +1,161 @@ +namespace SprutCAMPlugins; //Do not rename this namespace! + +using SprutTechnology.STLibraryTypes; +using System.Collections.Generic; +using System.Reflection; + +/// +/// Plugin class attributes. +/// The PluginID and PluginType attributes are required for plugin class instances. +/// +[AttributeUsage(AttributeTargets.Class)] +public class SprutCAMPluginAttribute: System.Attribute +{ + public string PluginID { get; set; } = Guid.Empty.ToString(); + public string PluginType { get; set; } = Guid.Empty.ToString(); + public string PluginCaption { get; set; } = ""; + public string PluginDescription { get; set; } = ""; +} + +/// +/// Base class for registering and calling plugins. +/// +public class CAMPluginsFactory : IST_CAMPluginsFactory +{ + public CAMPluginsFactory() + { + RegAllPlugins(); + } + + private void RegAllPlugins() + { + var a = Assembly.GetExecutingAssembly(); + foreach (TypeInfo c in a.DefinedTypes.Where(t => t.IsClass && t.IsPublic)) { + var atr = c.GetCustomAttribute(typeof(SprutCAMPluginAttribute)); + if (atr != null) { + var dsc = (SprutCAMPluginAttribute)atr; + TPluginsEnumerator.Plugins.Add(new PluginDescriptor( + new Guid(dsc.PluginType), + new Guid(dsc.PluginID), + c.AsType(), + dsc.PluginCaption, + dsc.PluginDescription + )); + } + } + } + + /// IST_CAMPluginsFactory + public IST_CAMPluginsEnumerator GetPluginsEnumeratorOfType(Guid PluginInterfaceID) + { + return new TPluginsEnumerator(PluginInterfaceID); + } + + /// IST_CAMPluginsFactory + public IST_CAMPlugin CreateInstanceOfPlugin(Guid PluginID) + { + return TPluginsEnumerator.CreateInstanceOfPlugin(PluginID); + } +} + +/// +/// The base abstract class of a plugins. +/// +public abstract class TAbstractPlugin : IST_CAMPlugin +{ + protected PluginDescriptor fDescriptor; + + public TAbstractPlugin() + { + foreach(var desc in TPluginsEnumerator.Plugins) { + if (desc.PluginClass.Equals(this.GetType())) { + fDescriptor = desc; + break; + } + } + } + + public Guid PluginID => fDescriptor.PluginID; + + public string PluginCaption => fDescriptor.PluginCaption; + + public string PluginDescription => fDescriptor.PluginDescription; +} + +/// +/// Basic Plugin Attributes Structure. +/// +public struct PluginDescriptor +{ + public Guid PluginType; + public Guid PluginID; + public Type PluginClass; + public string PluginCaption; + public string PluginDescription; + + public PluginDescriptor(Guid pluginType, Guid pluginID, Type pluginClass, string pluginCaption, string pluginDescription) + { + PluginType = pluginType; + PluginID = pluginID; + PluginClass = pluginClass; + PluginCaption = pluginCaption; + PluginDescription = pluginDescription; + } +} + +/// +/// Basic enumerator for working with registered plugins. +/// +public class TPluginsEnumerator : IST_CAMPluginsEnumerator +{ + int index; + Guid pluginType; + + public static List Plugins = new List(); + + public TPluginsEnumerator(Guid PluginType) + { + index = -1; + pluginType = PluginType; + } + + /// IST_CAMPluginsEnumerator + public bool MoveNext() + { + index++; + while (index < Plugins.Count) + { + PluginDescriptor dsc = Plugins[index]; + if (dsc.PluginType == pluginType) + break; + index++; + } + return index < Plugins.Count; + } + + /// IST_CAMPluginsEnumerator + public Guid GetCurrent() + { + if (index < Plugins.Count) + return Plugins[index].PluginID; + else + return Guid.Empty; + } + + private static int IndexOfPlugin(Guid pluginID) + { + for (int i = 0; i < Plugins.Count; i++) + if (Plugins[i].PluginID == pluginID) + return i; + return -1; + } + + public static IST_CAMPlugin CreateInstanceOfPlugin(Guid PluginID) + { + IST_CAMPlugin? result = null; + int i = IndexOfPlugin(PluginID); + if (i >= 0) + result = (IST_CAMPlugin)Activator.CreateInstance(Plugins[i].PluginClass)!; + return result; + } +} \ No newline at end of file diff --git a/STPluginsExample/Plugin1.cs b/STPluginsExample/Plugin1.cs new file mode 100644 index 0000000..2d2fffa --- /dev/null +++ b/STPluginsExample/Plugin1.cs @@ -0,0 +1,62 @@ +using SprutCAMPlugins; +using SprutTechnology.STLibraryTypes; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace PluginsExample +{ + /// Plugin class example. + /// The PluginID attribute must be unique. + /// The PluginType attribute must match the interface GUID, implemented in the plugin class. + /// All plugin classes must inherit from the TAbstractPlugin base class + /// and implement the IST_UtilitiesButtonCAMPlugin interface + /// (plugin interfaces may differ in their purpose). + [SprutCAMPlugin( + PluginID = "7581E851-9239-4820-A4DF-FBBADCAAD7DD", + PluginType = "4B74BB21-9F48-4D62-9870-0A831C8AD2DA", + PluginCaption = "Plugin 1 caption", + PluginDescription = "Plugin 1 description" + )] + public class TPlugin1Class : TAbstractPlugin, IST_UtilitiesButtonCAMPlugin + { + /// IST_UtilitiesButtonCAMPlugin + /// An event called when the plugin button is clicked in the SprutCAM client. + public void OnButtonClick(object SenderApplication) + { + //var app = (IST_Application) SenderApplication; + TUtils.ShowMessage("TPlugin1Class button click!", "PluginsExample", 0); + } + } + + /// Plugin class example. + [SprutCAMPlugin( + PluginID = "462D862C-2095-41DA-B79A-54D424194EA5", + PluginType = "4B74BB21-9F48-4D62-9870-0A831C8AD2DA", + PluginCaption = "Plugin 2 caption", + PluginDescription = "Plugin 2 description" + )] + public class TPlugin2Class : TAbstractPlugin, IST_UtilitiesButtonCAMPlugin + { + // IST_UtilitiesButtonCAMPlugin + /// An event called when the plugin button is clicked in the SprutCAM client. + public void OnButtonClick(object SenderApplication) + { + //var app = (IST_Application) SenderApplication; + TUtils.ShowMessage("TPlugin2Class button click!", "PluginsExample", 0); + } + } + + /// For example, not mandatory. + public class TUtils { + + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + public static extern int MessageBox(IntPtr h, string m, string c, int type); + + public static int ShowMessage(string message, string caption, int msgType) { + IntPtr handle = Process.GetCurrentProcess().MainWindowHandle; + int res = MessageBox(handle, message, caption, msgType); + return res; + } + } + +} \ No newline at end of file diff --git a/STPluginsExample/ReadMe.md b/STPluginsExample/ReadMe.md new file mode 100644 index 0000000..25d2cda --- /dev/null +++ b/STPluginsExample/ReadMe.md @@ -0,0 +1 @@ +This solution is under development \ No newline at end of file diff --git a/STPluginsExample/STPluginsExample.csproj b/STPluginsExample/STPluginsExample.csproj new file mode 100644 index 0000000..d159b66 --- /dev/null +++ b/STPluginsExample/STPluginsExample.csproj @@ -0,0 +1,17 @@ + + + + net6.0-windows + + true + enable + CS8603 + + + + + + + + +