diff --git a/API/RainmeterAPI.cs b/API/RainmeterAPI.cs index 72454c4..4490dd1 100644 --- a/API/RainmeterAPI.cs +++ b/API/RainmeterAPI.cs @@ -531,6 +531,60 @@ public void LogF(LogType type, string format, params Object[] args) RmLog(this.m_Rm, type, string.Format(format, args)); } } + + /// + /// Helper for returning strings back to Rainmeter as an IntPtr. + /// + /// + /// + /// [DllExport] + /// public static IntPtr GetString(IntPtr data) + /// { + /// return Rainmeter.StringBuffer.Update("hello"); + /// } + /// + /// + public sealed class StringBuffer + { + private static readonly StringBuffer s_Instance = new StringBuffer(); + + private IntPtr m_Buffer = IntPtr.Zero; + + static StringBuffer() + { + } + + private StringBuffer() + { + } + + ~StringBuffer() + { + FreeBuffer(); + } + + private void FreeBuffer() + { + if (m_Buffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(m_Buffer); + m_Buffer = IntPtr.Zero; + } + } + + public static IntPtr Update(string value) + { + s_Instance.FreeBuffer(); + s_Instance.m_Buffer = value != null ? Marshal.StringToHGlobalUni(value) : IntPtr.Zero; + return s_Instance.m_Buffer; + } + + public static IntPtr Get() + { + return s_Instance.m_Buffer; + } + } + /// /// Dummy attribute to mark method as exported for DllExporter.exe. /// diff --git a/C#/PluginEmpty/PluginEmpty.cs b/C#/PluginEmpty/PluginEmpty.cs index ecfa475..3064d11 100644 --- a/C#/PluginEmpty/PluginEmpty.cs +++ b/C#/PluginEmpty/PluginEmpty.cs @@ -5,10 +5,9 @@ // Overview: This is a blank canvas on which to build your plugin. -// Note: GetString, ExecuteBang and an unnamed function for use as a section variable +// Note: GetString, ExecuteBang and MyCustomFunction for use as a section variable // have been commented out. If you need GetString, ExecuteBang, and/or section variables -// and you have read what they are used for from the SDK docs, uncomment the function(s) -// and/or add a function name to use for the section variable function(s). +// and you have read what they are used for from the SDK docs, uncomment the function(s). // Otherwise leave them commented out (or get rid of them)! namespace PluginEmpty @@ -19,7 +18,8 @@ static public implicit operator Measure(IntPtr data) { return (Measure)GCHandle.FromIntPtr(data).Target; } - public IntPtr buffer = IntPtr.Zero; + + // Include your measure data/functions here. } public class Plugin @@ -35,10 +35,7 @@ public static void Initialize(ref IntPtr data, IntPtr rm) public static void Finalize(IntPtr data) { Measure measure = (Measure)data; - if (measure.buffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(measure.buffer); - } + GCHandle.FromIntPtr(data).Free(); } @@ -52,7 +49,6 @@ public static void Reload(IntPtr data, IntPtr rm, ref double maxValue) public static double Update(IntPtr data) { Measure measure = (Measure)data; - return 0.0; } @@ -60,15 +56,7 @@ public static double Update(IntPtr data) //public static IntPtr GetString(IntPtr data) //{ // Measure measure = (Measure)data; - // if (measure.buffer != IntPtr.Zero) - // { - // Marshal.FreeHGlobal(measure.buffer); - // measure.buffer = IntPtr.Zero; - // } - // - // measure.buffer = Marshal.StringToHGlobalUni(""); - // - // return measure.buffer; + // return Rainmeter.StringBuffer.Update(""); //} //[DllExport] @@ -78,19 +66,10 @@ public static double Update(IntPtr data) //} //[DllExport] - //public static IntPtr (IntPtr data, int argc, + //public static IntPtr MyCustomFunction(IntPtr data, int argc, // [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv) //{ - // Measure measure = (Measure)data; - // if (measure.buffer != IntPtr.Zero) - // { - // Marshal.FreeHGlobal(measure.buffer); - // measure.buffer = IntPtr.Zero; - // } - // - // measure.buffer = Marshal.StringToHGlobalUni(""); - // - // return measure.buffer; + // return Rainmeter.StringBuffer.Update(""); //} } } diff --git a/C#/PluginSectionVariables/PluginSectionVariables.cs b/C#/PluginSectionVariables/PluginSectionVariables.cs index 0cb11c0..e2a8f4b 100644 --- a/C#/PluginSectionVariables/PluginSectionVariables.cs +++ b/C#/PluginSectionVariables/PluginSectionVariables.cs @@ -1,19 +1,19 @@ /* -Copyright (C) 2017 Trevor Hamilton + Copyright (C) 2017 Trevor Hamilton -This program 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 2 -of the License, or (at your option) any later version. + This program 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 2 + of the License, or (at your option) any later version. -This program 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. + This program 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 this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ using System; @@ -68,8 +68,8 @@ static public implicit operator Measure(IntPtr data) { return (Measure)GCHandle.FromIntPtr(data).Target; } - public string inputStr; //The string returned in GetString is stored here - public IntPtr buffer; //Prevent marshalAs from causing memory leaks by clearing this before assigning + + public string inputStr; } public class Plugin @@ -87,7 +87,6 @@ public static void Reload(IntPtr data, IntPtr rm, ref double maxValue) Measure measure = (Measure)data; Rainmeter.API api = (Rainmeter.API)rm; - //Read measure for an Input string measure.inputStr = api.ReadString("Input", ""); } @@ -102,14 +101,7 @@ public static double Update(IntPtr data) public static IntPtr GetString(IntPtr data) { Measure measure = (Measure)data; - if (measure.buffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(measure.buffer); - measure.buffer = IntPtr.Zero; - } - - measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr); - return measure.buffer; + return Rainmeter.StringBuffer.Update(measure.inputStr); } [DllExport] @@ -117,23 +109,15 @@ public static IntPtr ToUpper(IntPtr data, int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv) { Measure measure = (Measure)data; - if (measure.buffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(measure.buffer); - measure.buffer = IntPtr.Zero; - } - //If we are given one or more arguments convert to uppercase the first one + // If we are given one or more arguments convert to uppercase the first one if (argc > 0) { - measure.buffer = Marshal.StringToHGlobalUni(argv[0].ToUpper()); - } - //If we are given no arguments convert to uppercase the string we recived with the input option - else - { - measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr.ToUpper()); + return Rainmeter.StringBuffer.Update(argv[0].ToUpper()); } - return measure.buffer; + + // If we are given no arguments convert to uppercase the string we recived with the input option + return Rainmeter.StringBuffer.Update(measure.inputStr.ToUpper()); } [DllExport] @@ -141,33 +125,19 @@ public static IntPtr ToLower(IntPtr data, int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv) { Measure measure = (Measure)data; - if (measure.buffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(measure.buffer); - measure.buffer = IntPtr.Zero; - } - //If we are given one or more arguments convert to uppercase the first one if (argc > 0) { - measure.buffer = Marshal.StringToHGlobalUni(argv[0].ToUpper()); - } - //If we are given no arguments convert to uppercase the string we recived with the input option - else - { - measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr.ToLower()); + return Rainmeter.StringBuffer.Update(argv[0].ToUpper()); } - return measure.buffer; + + return Rainmeter.StringBuffer.Update(measure.inputStr.ToLower()); } [DllExport] public static void Finalize(IntPtr data) { Measure measure = (Measure)data; - if (measure.buffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(measure.buffer); - } GCHandle.FromIntPtr(data).Free(); } } diff --git a/C#/PluginSystemVersion/PluginSystemVersion.cs b/C#/PluginSystemVersion/PluginSystemVersion.cs index 5d07c4c..e908375 100644 --- a/C#/PluginSystemVersion/PluginSystemVersion.cs +++ b/C#/PluginSystemVersion/PluginSystemVersion.cs @@ -161,8 +161,6 @@ internal string GetString() public static class Plugin { - static IntPtr StringBuffer = IntPtr.Zero; - [DllExport] public static void Initialize(ref IntPtr data, IntPtr rm) { @@ -173,12 +171,6 @@ public static void Initialize(ref IntPtr data, IntPtr rm) public static void Finalize(IntPtr data) { GCHandle.FromIntPtr(data).Free(); - - if (StringBuffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(StringBuffer); - StringBuffer = IntPtr.Zero; - } } [DllExport] @@ -199,19 +191,7 @@ public static double Update(IntPtr data) public static IntPtr GetString(IntPtr data) { Measure measure = (Measure)GCHandle.FromIntPtr(data).Target; - if (StringBuffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(StringBuffer); - StringBuffer = IntPtr.Zero; - } - - string stringValue = measure.GetString(); - if (stringValue != null) - { - StringBuffer = Marshal.StringToHGlobalUni(stringValue); - } - - return StringBuffer; + return Rainmeter.StringBuffer.Update(measure.GetString()); } } }