Skip to content

Commit 14b269f

Browse files
committed
Add Rainmeter.StringBuffer helper to C# SDK
This makes it easy to return strings in API functions like `GetString`.
1 parent 3b27e77 commit 14b269f

4 files changed

Lines changed: 87 additions & 103 deletions

File tree

API/RainmeterAPI.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,61 @@ public void LogF(LogType type, string format, params Object[] args)
531531
RmLog(this.m_Rm, type, string.Format(format, args));
532532
}
533533
}
534+
535+
/// <summary>
536+
/// Helper for returning strings back to Rainmeter as an IntPtr.
537+
/// </summary>
538+
/// <example>
539+
/// <code>
540+
/// [DllExport]
541+
/// public static IntPtr GetString(IntPtr data)
542+
/// {
543+
/// return Rainmeter.StringBuffer.Update("hello");
544+
/// }
545+
/// </code>
546+
/// </example>
547+
public sealed class StringBuffer
548+
{
549+
private static readonly StringBuffer s_Instance = new StringBuffer();
550+
551+
private IntPtr m_Buffer = IntPtr.Zero;
552+
553+
static StringBuffer()
554+
{
555+
}
556+
557+
private StringBuffer()
558+
{
559+
}
560+
561+
~StringBuffer()
562+
{
563+
FreeBuffer();
564+
}
565+
566+
private void FreeBuffer()
567+
{
568+
Console.WriteLine("FreeBuffer");
569+
if (m_Buffer != IntPtr.Zero)
570+
{
571+
Marshal.FreeHGlobal(m_Buffer);
572+
m_Buffer = IntPtr.Zero;
573+
}
574+
}
575+
576+
public static IntPtr Update(string value)
577+
{
578+
s_Instance.FreeBuffer();
579+
s_Instance.m_Buffer = value != null ? Marshal.StringToHGlobalUni(value) : IntPtr.Zero;
580+
return s_Instance.m_Buffer;
581+
}
582+
583+
public static IntPtr Get()
584+
{
585+
return s_Instance.m_Buffer;
586+
}
587+
}
588+
534589
/// <summary>
535590
/// Dummy attribute to mark method as exported for DllExporter.exe.
536591
/// </summary>

C#/PluginEmpty/PluginEmpty.cs

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55

66
// Overview: This is a blank canvas on which to build your plugin.
77

8-
// Note: GetString, ExecuteBang and an unnamed function for use as a section variable
8+
// Note: GetString, ExecuteBang and MyCustomFunction for use as a section variable
99
// have been commented out. If you need GetString, ExecuteBang, and/or section variables
10-
// and you have read what they are used for from the SDK docs, uncomment the function(s)
11-
// and/or add a function name to use for the section variable function(s).
10+
// and you have read what they are used for from the SDK docs, uncomment the function(s).
1211
// Otherwise leave them commented out (or get rid of them)!
1312

1413
namespace PluginEmpty
@@ -19,7 +18,8 @@ static public implicit operator Measure(IntPtr data)
1918
{
2019
return (Measure)GCHandle.FromIntPtr(data).Target;
2120
}
22-
public IntPtr buffer = IntPtr.Zero;
21+
22+
// Include your measure data/functions here.
2323
}
2424

2525
public class Plugin
@@ -35,10 +35,7 @@ public static void Initialize(ref IntPtr data, IntPtr rm)
3535
public static void Finalize(IntPtr data)
3636
{
3737
Measure measure = (Measure)data;
38-
if (measure.buffer != IntPtr.Zero)
39-
{
40-
Marshal.FreeHGlobal(measure.buffer);
41-
}
38+
4239
GCHandle.FromIntPtr(data).Free();
4340
}
4441

@@ -52,23 +49,14 @@ public static void Reload(IntPtr data, IntPtr rm, ref double maxValue)
5249
public static double Update(IntPtr data)
5350
{
5451
Measure measure = (Measure)data;
55-
5652
return 0.0;
5753
}
5854

5955
//[DllExport]
6056
//public static IntPtr GetString(IntPtr data)
6157
//{
6258
// Measure measure = (Measure)data;
63-
// if (measure.buffer != IntPtr.Zero)
64-
// {
65-
// Marshal.FreeHGlobal(measure.buffer);
66-
// measure.buffer = IntPtr.Zero;
67-
// }
68-
//
69-
// measure.buffer = Marshal.StringToHGlobalUni("");
70-
//
71-
// return measure.buffer;
59+
// return Rainmeter.StringBuffer.Update("");
7260
//}
7361

7462
//[DllExport]
@@ -78,19 +66,10 @@ public static double Update(IntPtr data)
7866
//}
7967

8068
//[DllExport]
81-
//public static IntPtr (IntPtr data, int argc,
69+
//public static IntPtr MyCustomFunction(IntPtr data, int argc,
8270
// [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv)
8371
//{
84-
// Measure measure = (Measure)data;
85-
// if (measure.buffer != IntPtr.Zero)
86-
// {
87-
// Marshal.FreeHGlobal(measure.buffer);
88-
// measure.buffer = IntPtr.Zero;
89-
// }
90-
//
91-
// measure.buffer = Marshal.StringToHGlobalUni("");
92-
//
93-
// return measure.buffer;
72+
// return Rainmeter.StringBuffer.Update("");
9473
//}
9574
}
9675
}

C#/PluginSectionVariables/PluginSectionVariables.cs

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
/*
2-
Copyright (C) 2017 Trevor Hamilton
2+
Copyright (C) 2017 Trevor Hamilton
33
4-
This program is free software; you can redistribute it and/or
5-
modify it under the terms of the GNU General Public License
6-
as published by the Free Software Foundation; either version 2
7-
of the License, or (at your option) any later version.
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
as published by the Free Software Foundation; either version 2
7+
of the License, or (at your option) any later version.
88
9-
This program is distributed in the hope that it will be useful,
10-
but WITHOUT ANY WARRANTY; without even the implied warranty of
11-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-
GNU General Public License for more details.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
1313
14-
You should have received a copy of the GNU General Public License
15-
along with this program; if not, write to the Free Software
16-
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717
*/
1818

1919
using System;
@@ -68,8 +68,8 @@ static public implicit operator Measure(IntPtr data)
6868
{
6969
return (Measure)GCHandle.FromIntPtr(data).Target;
7070
}
71-
public string inputStr; //The string returned in GetString is stored here
72-
public IntPtr buffer; //Prevent marshalAs from causing memory leaks by clearing this before assigning
71+
72+
public string inputStr;
7373
}
7474

7575
public class Plugin
@@ -87,7 +87,6 @@ public static void Reload(IntPtr data, IntPtr rm, ref double maxValue)
8787
Measure measure = (Measure)data;
8888
Rainmeter.API api = (Rainmeter.API)rm;
8989

90-
//Read measure for an Input string
9190
measure.inputStr = api.ReadString("Input", "");
9291
}
9392

@@ -102,72 +101,43 @@ public static double Update(IntPtr data)
102101
public static IntPtr GetString(IntPtr data)
103102
{
104103
Measure measure = (Measure)data;
105-
if (measure.buffer != IntPtr.Zero)
106-
{
107-
Marshal.FreeHGlobal(measure.buffer);
108-
measure.buffer = IntPtr.Zero;
109-
}
110-
111-
measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr);
112-
return measure.buffer;
104+
return Rainmeter.StringBuffer.Update(measure.inputStr);
113105
}
114106

115107
[DllExport]
116108
public static IntPtr ToUpper(IntPtr data, int argc,
117109
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv)
118110
{
119111
Measure measure = (Measure)data;
120-
if (measure.buffer != IntPtr.Zero)
121-
{
122-
Marshal.FreeHGlobal(measure.buffer);
123-
measure.buffer = IntPtr.Zero;
124-
}
125112

126-
//If we are given one or more arguments convert to uppercase the first one
113+
// If we are given one or more arguments convert to uppercase the first one
127114
if (argc > 0)
128115
{
129-
measure.buffer = Marshal.StringToHGlobalUni(argv[0].ToUpper());
130-
}
131-
//If we are given no arguments convert to uppercase the string we recived with the input option
132-
else
133-
{
134-
measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr.ToUpper());
116+
return Rainmeter.StringBuffer.Update(argv[0].ToUpper());
135117
}
136-
return measure.buffer;
118+
119+
// If we are given no arguments convert to uppercase the string we recived with the input option
120+
return Rainmeter.StringBuffer.Update(measure.inputStr.ToUpper());
137121
}
138122

139123
[DllExport]
140124
public static IntPtr ToLower(IntPtr data, int argc,
141125
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] argv)
142126
{
143127
Measure measure = (Measure)data;
144-
if (measure.buffer != IntPtr.Zero)
145-
{
146-
Marshal.FreeHGlobal(measure.buffer);
147-
measure.buffer = IntPtr.Zero;
148-
}
149128

150-
//If we are given one or more arguments convert to uppercase the first one
151129
if (argc > 0)
152130
{
153-
measure.buffer = Marshal.StringToHGlobalUni(argv[0].ToUpper());
154-
}
155-
//If we are given no arguments convert to uppercase the string we recived with the input option
156-
else
157-
{
158-
measure.buffer = Marshal.StringToHGlobalUni(measure.inputStr.ToLower());
131+
return Rainmeter.StringBuffer.Update(argv[0].ToUpper());
159132
}
160-
return measure.buffer;
133+
134+
return Rainmeter.StringBuffer.Update(measure.inputStr.ToLower());
161135
}
162136

163137
[DllExport]
164138
public static void Finalize(IntPtr data)
165139
{
166140
Measure measure = (Measure)data;
167-
if (measure.buffer != IntPtr.Zero)
168-
{
169-
Marshal.FreeHGlobal(measure.buffer);
170-
}
171141
GCHandle.FromIntPtr(data).Free();
172142
}
173143
}

C#/PluginSystemVersion/PluginSystemVersion.cs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,6 @@ internal string GetString()
161161

162162
public static class Plugin
163163
{
164-
static IntPtr StringBuffer = IntPtr.Zero;
165-
166164
[DllExport]
167165
public static void Initialize(ref IntPtr data, IntPtr rm)
168166
{
@@ -173,12 +171,6 @@ public static void Initialize(ref IntPtr data, IntPtr rm)
173171
public static void Finalize(IntPtr data)
174172
{
175173
GCHandle.FromIntPtr(data).Free();
176-
177-
if (StringBuffer != IntPtr.Zero)
178-
{
179-
Marshal.FreeHGlobal(StringBuffer);
180-
StringBuffer = IntPtr.Zero;
181-
}
182174
}
183175

184176
[DllExport]
@@ -199,19 +191,7 @@ public static double Update(IntPtr data)
199191
public static IntPtr GetString(IntPtr data)
200192
{
201193
Measure measure = (Measure)GCHandle.FromIntPtr(data).Target;
202-
if (StringBuffer != IntPtr.Zero)
203-
{
204-
Marshal.FreeHGlobal(StringBuffer);
205-
StringBuffer = IntPtr.Zero;
206-
}
207-
208-
string stringValue = measure.GetString();
209-
if (stringValue != null)
210-
{
211-
StringBuffer = Marshal.StringToHGlobalUni(stringValue);
212-
}
213-
214-
return StringBuffer;
194+
return Rainmeter.StringBuffer.Update(measure.GetString());
215195
}
216196
}
217197
}

0 commit comments

Comments
 (0)