InputText.dll: Updated to new API

This commit is contained in:
spx 2013-03-01 16:26:05 +09:00
parent 7186f0988a
commit 5eafccdba7
6 changed files with 414 additions and 1022 deletions

View File

@ -2,6 +2,6 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("© 2010 - Peter Souza IV")] [assembly: AssemblyCopyright("© 2010 - Peter Souza IV")]
[assembly: AssemblyVersion("1.6.0.0")] [assembly: AssemblyVersion("1.7.0.0")]
[assembly: AssemblyInformationalVersion(Rainmeter.Version.Informational)] [assembly: AssemblyInformationalVersion(Rainmeter.Version.Informational)]
[assembly: AssemblyProduct("Rainmeter")] [assembly: AssemblyProduct("Rainmeter")]

View File

@ -1,4 +1,22 @@
using System; /*
Copyright (C) 2013 Rainmeter Team
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.
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;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
@ -6,14 +24,17 @@ namespace InputText
{ {
public partial class InputBox : Form public partial class InputBox : Form
{ {
public Rainmeter.Settings.InstanceSettings Instance = null; private SkinWindow parent = null;
#region Default form initializer private bool _FocusDismiss = true;
public InputBox() private string _TextValue = string.Empty;
public InputBox(SkinWindow parent)
{ {
this.parent = parent;
InitializeComponent(); InitializeComponent();
} }
#endregion
// This event will make sure we have focus when the inputbox is shown ot the user. // This event will make sure we have focus when the inputbox is shown ot the user.
// it will only cause focus if the window itself has focus (i.e. doesn't steal). // it will only cause focus if the window itself has focus (i.e. doesn't steal).
@ -26,6 +47,14 @@ namespace InputText
this.txtInput.Focus(); this.txtInput.Focus();
} }
private void InputBox_Load(object sender, EventArgs e)
{
this.Activate();
this.BringToFront();
this.Activate();
this.BringToFront();
}
// All exceptions are swallowed for the sake of this example. Since the majority // All exceptions are swallowed for the sake of this example. Since the majority
// (if not all) of these are rather simple in nature, debugging without errors // (if not all) of these are rather simple in nature, debugging without errors
// should be fairly simple anyway. // should be fairly simple anyway.
@ -39,16 +68,13 @@ namespace InputText
// } // }
// catch (Exception ex) // catch (Exception ex)
// { // {
// Rainmeter.Log(Rainmeter.LogLevel.Warning, "InputText :: exception :: " + ex.GetType().ToString() + ": " + ex.Message); // API.Log(API.LogType.Warning, "InputText :: exception :: " + ex.GetType().ToString() + ": " + ex.Message);
// } // }
#region TextInput -- returns the inputted text #region TextValue -- returns the inputted text
public string TextInput public string TextValue
{ {
get get { return this._TextValue; }
{
return this.txtInput.Text.Trim();
}
} }
#endregion #endregion
#region ChangeFontFace(string) -- changes the text's font name #region ChangeFontFace(string) -- changes the text's font name
@ -170,10 +196,10 @@ namespace InputText
this.TopMost = true; this.TopMost = true;
} }
#endregion #endregion
#region MakePassword() -- causes the textbox to be password style #region MakePassword(bool) -- causes the textbox to be password style
public void MakePassword() public void MakePassword(bool bPass)
{ {
this.txtInput.PasswordChar = '*'; this.txtInput.PasswordChar = bPass ? '*' : '\0';
} }
#endregion #endregion
#region ChangeFontStringStyle() -- changes the font's bold/italic styles #region ChangeFontStringStyle() -- changes the font's bold/italic styles
@ -216,7 +242,7 @@ namespace InputText
} }
#endregion #endregion
#region ChangeX(string) -- changes the X (horizontal) position of the input textbox, relative to its parent skin #region ChangeX(string) -- changes the X (horizontal) position of the input textbox, relative to its parent skin
public void ChangeX(Rainmeter.Settings.InstanceSettings Instance, string sX) public void ChangeX(string sX)
{ {
try try
{ {
@ -227,13 +253,13 @@ namespace InputText
// Notice that we need the position of the parent window for offset location. // Notice that we need the position of the parent window for offset location.
// //
// The Rainmeter class does this for us // The Rainmeter class does this for us
this.Location = new System.Drawing.Point(Rainmeter.ConfigX(Rainmeter.SkinName(Instance)) + int.Parse(sX), this.Location.Y); this.Location = new System.Drawing.Point(this.parent.X + int.Parse(sX), this.Location.Y);
} }
catch { } catch { }
} }
#endregion #endregion
#region ChangeY(string) -- changes the Y (vertical) position of the input textbox, relative to its parent skin #region ChangeY(string) -- changes the Y (vertical) position of the input textbox, relative to its parent skin
public void ChangeY(Rainmeter.Settings.InstanceSettings Instance, string sY) public void ChangeY(string sY)
{ {
try try
{ {
@ -244,7 +270,7 @@ namespace InputText
// Notice that we need the position of the parent window for offset location. // Notice that we need the position of the parent window for offset location.
// //
// The Rainmeter class does this for us // The Rainmeter class does this for us
this.Location = new System.Drawing.Point(this.Location.X, Rainmeter.ConfigY(Rainmeter.SkinName(Instance)) + int.Parse(sY)); this.Location = new System.Drawing.Point(this.Location.X, this.parent.Y + int.Parse(sY));
} }
catch { } catch { }
} }
@ -256,15 +282,47 @@ namespace InputText
} }
#endregion #endregion
#region MakeFocusDismiss(bool) -- dismisses the input textbox if it loses cursor/window focus #region MakeFocusDismiss(bool) -- dismisses the input textbox if it loses cursor/window focus
private bool _FocusDismiss = true;
public DialogResult drBackup = DialogResult.None;
public string sTextValue = string.Empty;
public void MakeFocusDismiss(bool bDismissing) public void MakeFocusDismiss(bool bDismissing)
{ {
this._FocusDismiss = bDismissing; this._FocusDismiss = bDismissing;
} }
#endregion
#region ShowInputBox() -- shows text input textbox
private DialogResult drBackup = DialogResult.None;
public bool ShowInputBox()
{
if (this._FocusDismiss)
{
this.Show(this.parent);
while (this.DialogResult == DialogResult.None &&
this.drBackup == DialogResult.None)
{
Application.DoEvents();
System.Threading.Thread.Sleep(44);
}
}
else
{
this.ShowDialog(this.parent);
}
if (this.drBackup != DialogResult.None)
{
if (this.drBackup != DialogResult.OK)
return false;
}
else if (this.DialogResult != DialogResult.None)
{
if (this.DialogResult != DialogResult.OK)
return false;
}
return true;
}
private void txtInput_Leave(object sender, EventArgs e) private void txtInput_Leave(object sender, EventArgs e)
{ {
@ -295,8 +353,8 @@ namespace InputText
private void btnOK_Click(object sender, EventArgs e) private void btnOK_Click(object sender, EventArgs e)
{ {
_FocusDismiss = false; this._FocusDismiss = false;
this.sTextValue = this.txtInput.Text.Trim(); this._TextValue = this.txtInput.Text.Trim();
this.drBackup = DialogResult.OK; this.drBackup = DialogResult.OK;
this.DialogResult = DialogResult.OK; this.DialogResult = DialogResult.OK;
this.Close(); this.Close();
@ -304,20 +362,12 @@ namespace InputText
private void btnCancel_Click(object sender, EventArgs e) private void btnCancel_Click(object sender, EventArgs e)
{ {
_FocusDismiss = false; this._FocusDismiss = false;
this.drBackup = DialogResult.Cancel; this.drBackup = DialogResult.Cancel;
this.DialogResult = DialogResult.Cancel; this.DialogResult = DialogResult.Cancel;
this.Close(); this.Close();
} }
#endregion #endregion
private void InputBox_Load(object sender, EventArgs e)
{
this.Activate();
this.BringToFront();
this.Activate();
this.BringToFront();
}
} }
} }

View File

@ -1,173 +1,148 @@
using System; /*
Copyright (C) 2013 Rainmeter Team
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.
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;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using Rainmeter; using Rainmeter;
namespace InputText namespace InputText
{ {
public class Main internal partial class Measure
{ {
/// <summary> private Rainmeter.API rm;
/// Your name (author) and the version of the plugin go here. The code will
/// automatically format the values and send them back when a call to GetAuthor()
/// or GetVersion() is made.
///
/// Optionally, you may also provide an e-mail address and additional comments
/// </summary>
private static Rainmeter.Settings Plugin = new Rainmeter.Settings
(
// Author name
"Peter Souza IV",
// Version private string LastInput = string.Empty;
1.06, private bool IsExecuteBangRunning = false;
// E-mail private object locker = new object();
"psouza4@gmail.com",
// Comments (try to keep it under 50 characters) internal Measure(Rainmeter.API rm)
"Please visit the forums for support."
);
#region GetAuthor() and GetVersion() exports -- no need to modify
[DllExport]
public static UInt32 GetPluginVersion()
{ {
return Rainmeter.Version(Plugin.Version); this.rm = rm;
} }
[DllExport] internal void Reload(Rainmeter.API rm, ref double maxValue)
public unsafe static char* GetPluginAuthor()
{ {
if (!string.IsNullOrEmpty(Plugin.Email) && !string.IsNullOrEmpty(Plugin.Comments)) // Do nothing here.
return Rainmeter.String(Plugin.Author + " (" + Plugin.Email + "): " + Plugin.Comments);
if (!string.IsNullOrEmpty(Plugin.Email))
return Rainmeter.String(Plugin.Author + " (" + Plugin.Email + ")");
if (!string.IsNullOrEmpty(Plugin.Comments))
return Rainmeter.String(Plugin.Author + ": " + Plugin.Comments);
return Rainmeter.String(Plugin.Author);
} }
#endregion internal double Update()
#region Initialize() and Finalize() -- you may add to these functions if necessary
[DllExport]
public unsafe static UInt32 Initialize(IntPtr instance, char* iniFile, char* section, UInt32 id)
{ {
Plugin.AddInstance(iniFile, section, id); // required: do not remove return 0.0;
////////////////////////////////////////////////////////////////
//
// You may add code here, if necessary
//
////////////////////////////////////////////////////////////////
return 0;
} }
[DllExport] internal string GetString()
public static void Finalize(IntPtr instance, UInt32 id)
{ {
Plugin.RemoveInstance(id); // required: do not remove lock (this.locker)
{
//////////////////////////////////////////////////////////////// return this.LastInput;
// }
// You may add code here, if necessary
//
////////////////////////////////////////////////////////////////
return;
}
#endregion
#region Update(), Update2(), and GetString() exports -- please read notes
// *** WARNING / NOTES ***
//
// Do not add to this code: change your code in PluginCode.cs instead
//
// However, due to the way Rainmeter works, you will probably want to
// comment-out either 'Update' or 'Update2' if your plugin will be returning
// numeric values.
//
// Rainmeter will look for 'Update' for positive integers. If you want to
// allow negative numbers or floating-point numbers, use 'Update2' instead.
//
// You *MUST* comment-out whichever function you don't want to use for this
// to work.
//
// If you don't care, such as a plugin that either doesn't return data or
// only returns string/text data, then you can leave them both here (it won't
// hurt anything).
//
// *** WARNING / NOTES ***
/// <summary>
/// Rainmeter's request for numeric data from the plugin. This version can only
/// return positive integers ranging from 0 to 4,294,967,296. Comment this member
/// out and use 'Update2' if you want to return negative or floating-point values.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <returns>Current value for this meter.</returns>
[DllExport]
public static UInt32 Update(UInt32 id)
{
// Do not modify this member (although you can comment it out). Instead, update
// your code in 'PluginCode.cs'.
return new YourPlugin().Update(Plugin, id);
} }
/// <summary> internal void ExecuteBang(string args)
/// Rainmeter's request for numeric data from the plugin. This version can return
/// positive or negative floating-point numbers (32-bit precision). Comment this
/// member out and use 'Update' if you want to only return positive integers.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <returns>Current value for this meter.</returns>
//[DllExport]
//public static double Update2(UInt32 id)
//{
// // Do not modify this member (although you can comment it out). Instead, update
// // your code in 'PluginCode.cs'.
// return new YourPlugin().Update2(Plugin, id);
//}
/// <summary>
/// Rainmeter's request for text data from the plugin.
/// </summary>
/// <param name="id">The unique instance ID of this request.</param>
/// <param name="flags">Unused still as of Dec 2nd, 2010.</param>
/// <returns></returns>
[DllExport]
public unsafe static char* GetString(UInt32 id, UInt32 flags)
{ {
// Do not modify this member. Instead, update your code in 'PluginCode.cs'. bool go = false;
return Rainmeter.String(new YourPlugin().GetString(Plugin, id));
lock (this.locker)
{
if (!this.IsExecuteBangRunning)
{
this.IsExecuteBangRunning = true;
go = true;
}
}
if (go)
{
ThreadPool.QueueUserWorkItem(ExecuteBangThread, args);
}
} }
#endregion private void ExecuteBangThread(object state)
#region ExecuteBang() export -- no need to modify (change code in PluginCode.cs)
[DllExport]
public static unsafe void ExecuteBang(char* args, UInt32 id)
{ {
new YourPlugin().ExecuteBang(Plugin, id, new string(args)); string command = (string)state;
return;
}
#endregion try
{
ExecuteCommands(command);
}
catch (Exception ex)
{
API.Log(API.LogType.Error, "C# plugin in ExecuteBang(), " + ex.GetType().ToString() + ": " + ex.Message);
}
lock (this.locker)
{
this.IsExecuteBangRunning = false;
}
}
} }
/// <summary> #region Plugin
/// Dummy attribute to mark method as exported for DllExporter.exe.
/// </summary> public static class Plugin
[AttributeUsage(AttributeTargets.Method)]
public class DllExport : Attribute
{ {
public DllExport() internal static Dictionary<uint, Measure> Measures = new Dictionary<uint, Measure>();
[DllExport]
public unsafe static void Initialize(void** data, void* rm)
{ {
uint id = (uint)((void*)*data);
Measures.Add(id, new Measure(new Rainmeter.API((IntPtr)rm)));
}
[DllExport]
public unsafe static void Finalize(void* data)
{
uint id = (uint)data;
Measures.Remove(id);
}
[DllExport]
public unsafe static void Reload(void* data, void* rm, double* maxValue)
{
uint id = (uint)data;
Measures[id].Reload(new Rainmeter.API((IntPtr)rm), ref *maxValue);
}
[DllExport]
public unsafe static double Update(void* data)
{
uint id = (uint)data;
return Measures[id].Update();
}
[DllExport]
public unsafe static char* GetString(void* data)
{
uint id = (uint)data;
fixed (char* s = Measures[id].GetString()) return s;
}
[DllExport]
public unsafe static void ExecuteBang(void* data, char* args)
{
uint id = (uint)data;
Measures[id].ExecuteBang(new string(args));
} }
} }
#endregion
} }

View File

@ -1,63 +1,68 @@
using System; /*
Copyright (C) 2013 Rainmeter Team
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.
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;
using System.Collections.Generic; using System.Collections.Generic;
using Rainmeter;
// The bulk of your plugin's code belongs in this file. // The bulk of your plugin's code belongs in this file.
namespace InputText namespace InputText
{ {
class PluginCode internal partial class Measure
{ {
// 'Update', 'Update2', and 'GetString' all return data back to Rainmeter, depending on private void ExecuteCommands(string Command)
// if the Rainmeter measure wants a numeric value or a string/text data.
//
// The 'Instance' member contains all of the data necessary to read the INI file
// passed to your plugin when this instance was first initialized. Remember: your plugin
// may be initialized multiple times. For example, a plugin that reads the free space
// of a hard drive may be called multiple times -- once for each installed hard drive.
public UInt32 Update(Rainmeter.Settings.InstanceSettings Instance)
{ {
return 0; Command = Command.Trim();
}
//public double Update2(Rainmeter.Settings.InstanceSettings Instance) // Get default options
//{ Dictionary<string, string> Options = new Dictionary<string, string>();
// return 0.0; ReadOption("DefaultValue", Options);
//} ReadOption("X", Options);
ReadOption("Y", Options);
ReadOption("W", Options);
ReadOption("H", Options);
ReadOption("StringStyle", Options);
ReadOption("StringAlign", Options);
ReadOption("FocusDismiss", Options);
ReadOption("FontColor", Options);
ReadOption("FontFace", Options);
ReadOption("FontSize", Options);
ReadOption("SolidColor", Options);
ReadOption("Password", Options);
ReadOption("TopMost", Options);
public string GetString(Rainmeter.Settings.InstanceSettings Instance)
{
// This plugin is unique as it is one of the first to not be used to display data
// back in Rainmeter, but to request user input and use that input during batch
// operations (and other purposes).
//
// However, Rainmeter requires that data be sent back, so we'll return temporary data
// In this case, the data is whatever the user last entered into an input textbox.
return Instance.GetTempValue("LastInput", string.Empty).ToString();
}
// 'ExecuteBang' is a way of Rainmeter telling your plugin to do something *right now*.
// What it wants to do can be defined by the 'Command' parameter.
public void ExecuteBang(Rainmeter.Settings.InstanceSettings Instance, string Command)
{
#region Handle a single parameter #region Handle a single parameter
// If our parameter list only contains a single word, then open a textbox immediately // If our parameter list only contains a single word, then open a textbox immediately
// and set a value. This mode does not do any batching. // and set a value. This mode does not do any batching.
if (!Command.Trim().Contains(" ")) if (!Command.Contains(" "))
{ {
// Assume that the parameter is the name of the variable // Assume that the parameter is the name of the variable
string sVariableName = Command.Trim();
// Ask for input // Ask for input
string sInput = GetUserInput(Instance); string sInput = GetUserInput(Options);
// If the user cancelled out of the inputbox (ESC key, etc.), then abort // If the user cancelled out of the inputbox (ESC key, etc.), then abort
if (sInput == null) if (sInput == null)
return; return;
// Ask Rainmeter to set the variable using a bang (http://rainmeter.net/RainCMS/?q=Bangs) // Ask Rainmeter to set the variable using a bang (http://rainmeter.net/RainCMS/?q=Bangs)
Rainmeter.Bang("!RainmeterSetVariable " + sVariableName + " \"" + sInput.Replace("\"", "\\\"") + "\""); API.Execute(rm.GetSkin(), "!SetVariable " + Command + " \"" + sInput + "\"");
// Note that the skin needs DynamicVariables=1 in the measure's settings or the above // Note that the skin needs DynamicVariables=1 in the measure's settings or the above
// code will have no effect. // code will have no effect.
@ -68,7 +73,7 @@ namespace InputText
#region Handle multiple parameters #region Handle multiple parameters
// Our parameter list contains at least two words, so split them up // Our parameter list contains at least two words, so split them up
string[] sParts = Command.Trim().Split(new string[] { " " }, StringSplitOptions.None); string[] sParts = Command.Split(new string[] { " " }, StringSplitOptions.None);
// If the first parameter is 'ExecuteBatch' (not case sensitive)... // If the first parameter is 'ExecuteBatch' (not case sensitive)...
if (sParts[0].Trim().ToUpper() == "EXECUTEBATCH") if (sParts[0].Trim().ToUpper() == "EXECUTEBATCH")
@ -126,18 +131,25 @@ namespace InputText
#region Parse commands in range #region Parse commands in range
// Parse each command in the range, aborting if any line returns 'false' or // Parse each command in the range, aborting if any line returns 'false' or
// the requested command line does not exist in the config for that measure. // the requested command line does not exist in the config for that measure.
List<string> commands = new List<string>();
for (int i = iMin; i <= iMax; i++) for (int i = iMin; i <= iMax; i++)
{ {
// Read this command's line // Read this command's line
string sCurrentLine = Instance.INI_Value("Command" + i.ToString()); string sCurrentLine = rm.ReadString("Command" + i.ToString(), "", false);
// If empty/non-existent, abort // If empty/non-existent, abort
if (string.IsNullOrEmpty(sCurrentLine)) if (string.IsNullOrEmpty(sCurrentLine))
break; break;
commands.Add(sCurrentLine);
}
foreach (string sCurrentLine in commands)
{
// Execute the line, but if there's a problem (error or they cancel the // Execute the line, but if there's a problem (error or they cancel the
// input textbox), then abort // input textbox), then abort
if (!ExecuteLine(Instance, sCurrentLine)) if (!ExecuteLine(sCurrentLine, Options))
break; break;
// Continue to the next line, if there is any // Continue to the next line, if there is any
@ -147,7 +159,7 @@ namespace InputText
} }
// Unhandled command, log the message but otherwise do nothing // Unhandled command, log the message but otherwise do nothing
Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled"); API.Log(API.LogType.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled");
#endregion #endregion
@ -157,7 +169,7 @@ namespace InputText
#region This is all code custom to this plugin #region This is all code custom to this plugin
#region Parse the current command line #region Parse the current command line
private bool ExecuteLine(Rainmeter.Settings.InstanceSettings Instance, string sLine) private bool ExecuteLine(string sLine, Dictionary<string, string> Options)
{ {
// If this line contains a $UserInput$ token, then we need to do some extra // If this line contains a $UserInput$ token, then we need to do some extra
// parsing // parsing
@ -186,17 +198,17 @@ namespace InputText
sLine = ScanAndReplace(sLine, "FocusDismiss", Overrides); sLine = ScanAndReplace(sLine, "FocusDismiss", Overrides);
sLine = ScanAndReplace(sLine, "FontColor", Overrides); sLine = ScanAndReplace(sLine, "FontColor", Overrides);
sLine = ScanAndReplace(sLine, "FontFace", Overrides); sLine = ScanAndReplace(sLine, "FontFace", Overrides);
sLine = ScanAndReplace(sLine, "FontSize", Overrides);
sLine = ScanAndReplace(sLine, "SolidColor", Overrides); sLine = ScanAndReplace(sLine, "SolidColor", Overrides);
sLine = ScanAndReplace(sLine, "Password", Overrides); sLine = ScanAndReplace(sLine, "Password", Overrides);
sLine = ScanAndReplace(sLine, "FontSize", Overrides);
sLine = ScanAndReplace(sLine, "TopMost", Overrides); sLine = ScanAndReplace(sLine, "TopMost", Overrides);
#endregion #endregion
// Get user input // Get user input
string sInput = GetUserInput(Instance, Overrides); string sInput = GetUserInput(Options, Overrides);
if (sInput == null) if (sInput == null)
{ {
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Aborted, user cancelled text box"); // API.Log(API.LogType.Debug, "InputText: Aborted, user cancelled text box");
return false; return false;
} }
@ -206,168 +218,116 @@ namespace InputText
catch (Exception ex) catch (Exception ex)
{ {
// If there was an error doing any of the above, log it for debugging purposes. // If there was an error doing any of the above, log it for debugging purposes.
Rainmeter.Log(Rainmeter.LogLevel.Warning, "InputText: Exception " + ex.GetType().ToString() + ": " + ex.Message); API.Log(API.LogType.Warning, "InputText: Exception " + ex.GetType().ToString() + ": " + ex.Message);
return false; return false;
} }
} }
// Execute the bang. This will either be the original line from CommandX= (sLine variable) or // Execute the bang. This will either be the original line from CommandX= (sLine variable) or
// an adjusted line based on special parsing above. // an adjusted line based on special parsing above.
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Executing bang: " + sLine); // API.Log(API.LogType.Debug, "InputText: Executing bang: " + sLine);
Rainmeter.Bang(sLine); API.Execute(rm.GetSkin(), sLine);
return true; return true;
} }
#endregion #endregion
#region GetUserInput() -- creates an input textbox and handles all INI and override settings #region GetUserInput() -- creates an input textbox and handles all INI and override settings
private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance) delegate void ChangeSettingFromString(string value);
delegate void ChangeInputBoxSetting(string option, ChangeSettingFromString method);
private string GetUserInput(Dictionary<string, string> Options)
{ {
// No INI overrides provided, so create an empty list // No INI overrides provided, so create an empty list
return GetUserInput(Instance, new Dictionary<string,string>()); return GetUserInput(Options, new Dictionary<string, string>());
} }
private string GetUserInput(Rainmeter.Settings.InstanceSettings Instance, Dictionary<string,string> sOverrides) private string GetUserInput(Dictionary<string, string> Options, Dictionary<string, string> Overrides)
{ {
SkinWindow skin = new SkinWindow(rm);
// Create the form. 'InputBox' is a .NET form with a textbox and two button controls on it. // Create the form. 'InputBox' is a .NET form with a textbox and two button controls on it.
InputBox input = new InputBox(); InputBox input = new InputBox(skin);
input.Instance = Instance; input.ChangeX("0");
input.ChangeX(Instance, "0"); input.ChangeY("0");
input.ChangeY(Instance, "0");
// Change the styles of the InputBox form based on overrides or INI values // Change the styles of the InputBox form based on overrides or INI values
#region Style and preference tweaks (INI and override settings) #region Style and preference tweaks (INI and override settings)
if (sOverrides.ContainsKey("FontFace")) ChangeInputBoxSetting changeSetting = (opt, change) =>
input.ChangeFontFace(sOverrides["FontFace"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontFace")))
input.ChangeFontFace(Instance.INI_Value("FontFace"));
if (sOverrides.ContainsKey("FontSize"))
input.ChangeFontSize(sOverrides["FontSize"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontSize")))
input.ChangeFontSize(Instance.INI_Value("FontSize"));
if (sOverrides.ContainsKey("W"))
input.ChangeW(sOverrides["W"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("W")))
input.ChangeW(Instance.INI_Value("W"));
if (sOverrides.ContainsKey("H"))
input.ChangeH(sOverrides["H"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("H")))
input.ChangeH(Instance.INI_Value("H"));
if (sOverrides.ContainsKey("X"))
input.ChangeX(Instance, sOverrides["X"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("X")))
input.ChangeX(Instance, Instance.INI_Value("X"));
if (sOverrides.ContainsKey("Y"))
input.ChangeY(Instance, sOverrides["Y"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("Y")))
input.ChangeY(Instance, Instance.INI_Value("Y"));
if (sOverrides.ContainsKey("StringStyle"))
input.ChangeFontStringStyle(sOverrides["StringStyle"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("StringStyle")))
input.ChangeFontStringStyle(Instance.INI_Value("StringStyle"));
if (sOverrides.ContainsKey("StringAlign"))
input.ChangeStringAlign(sOverrides["StringAlign"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("StringAlign")))
input.ChangeStringAlign(Instance.INI_Value("StringAlign"));
bool bFocusDismiss = true;
if (sOverrides.ContainsKey("FocusDismiss"))
{ {
input.MakeFocusDismiss(sOverrides["FocusDismiss"] == "1"); if (Overrides.ContainsKey(opt))
bFocusDismiss = sOverrides["FocusDismiss"] == "1"; change(Overrides[opt]);
} else if (Options.ContainsKey(opt))
else change(Options[opt]);
};
changeSetting("FontFace", input.ChangeFontFace);
changeSetting("FontSize", input.ChangeFontSize);
changeSetting("W", input.ChangeW);
changeSetting("H", input.ChangeH);
changeSetting("X", input.ChangeX);
changeSetting("Y", input.ChangeY);
changeSetting("StringStyle", input.ChangeFontStringStyle);
changeSetting("StringAlign", input.ChangeStringAlign);
changeSetting("FontColor", input.ChangeFontColor);
changeSetting("SolidColor", input.ChangeBackColor);
if (Overrides.ContainsKey("FocusDismiss"))
input.MakeFocusDismiss(Overrides["FocusDismiss"] == "1");
else if (Options.ContainsKey("FocusDismiss"))
input.MakeFocusDismiss(Options["FocusDismiss"].Trim() == "1");
if (Overrides.ContainsKey("Password"))
input.MakePassword(Overrides["Password"] == "1");
else if (Options.ContainsKey("Password"))
input.MakePassword(Options["Password"].Trim() == "1");
string topmost = null;
if (Overrides.ContainsKey("TopMost"))
topmost = Overrides["TopMost"];
else if (Options.ContainsKey("TopMost"))
topmost = Options["TopMost"].Trim();
switch (topmost)
{ {
input.MakeFocusDismiss(!(Instance.INI_Value("FocusDismiss").Trim().ToUpper() != "1")); case "1":
bFocusDismiss = !(Instance.INI_Value("FocusDismiss").Trim().ToUpper() != "1");
}
if (sOverrides.ContainsKey("FontColor"))
input.ChangeFontColor(sOverrides["FontColor"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("FontColor")))
input.ChangeFontColor(Instance.INI_Value("FontColor"));
if (sOverrides.ContainsKey("SolidColor"))
input.ChangeBackColor(sOverrides["SolidColor"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("SolidColor")))
input.ChangeBackColor(Instance.INI_Value("SolidColor"));
if (sOverrides.ContainsKey("Passwords"))
{
if (sOverrides["DefaultValue"] == "1")
input.MakePassword();
}
else if (Instance.INI_Value("Password").Trim().ToUpper() == "1")
input.MakePassword();
bool bAutoTopMost = true;
if (sOverrides.ContainsKey("TopMost"))
{
if (sOverrides["TopMost"] == "1")
{
input.MakeTopmost(); input.MakeTopmost();
bAutoTopMost = false; break;
} case "0":
else if (sOverrides["TopMost"] == "0") break;
bAutoTopMost = false; default: // AUTO
if (skin.IsTopmost)
input.MakeTopmost();
break;
} }
else if (Instance.INI_Value("TopMost").Trim().ToUpper() == "1")
{
input.MakeTopmost();
bAutoTopMost = false;
}
else if (Instance.INI_Value("TopMost").Trim().ToUpper() != "AUTO")
if (!string.IsNullOrEmpty(Instance.INI_Value("TopMost").Trim()))
bAutoTopMost = false;
if (bAutoTopMost)
if (Rainmeter.ParentIsTopmost(Instance))
input.MakeTopmost();
if (sOverrides.ContainsKey("DefaultValue")) changeSetting("DefaultValue", input.DefaultValue);
input.DefaultValue(sOverrides["DefaultValue"]);
else if (!string.IsNullOrEmpty(Instance.INI_Value("DefaultValue")))
input.DefaultValue(Instance.INI_Value("DefaultValue").Trim());
#endregion #endregion
if (bFocusDismiss) if (!input.ShowInputBox())
{ return null;
input.Show(new WindowWrapper(Rainmeter.GetConfigWindow(Instance)));
for (; ; ) lock (this.locker)
{
if (input.DialogResult != System.Windows.Forms.DialogResult.None || input.drBackup != System.Windows.Forms.DialogResult.None)
break;
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(44);
}
}
else
{ {
input.ShowDialog(new WindowWrapper(Rainmeter.GetConfigWindow(Instance))); this.LastInput = input.TextValue;
} }
return input.TextValue;
if (input.drBackup != System.Windows.Forms.DialogResult.None)
{
if (input.drBackup != System.Windows.Forms.DialogResult.OK)
return null;
}
else if (input.DialogResult != System.Windows.Forms.DialogResult.None)
{
if (input.DialogResult != System.Windows.Forms.DialogResult.OK)
return null;
}
Instance.SetTempValue("LastInput", input.sTextValue);
return input.sTextValue;
} }
#endregion #endregion
#region ReadOption() -- reads given option's value from Rainmeter
private void ReadOption(string optionName, Dictionary<string, string> Options)
{
string value = rm.ReadString(optionName, "");
if (!string.IsNullOrEmpty(value))
{
Options.Add(optionName, value);
}
}
#endregion
#region Replace() -- case-insensitive string replacement #region Replace() -- case-insensitive string replacement
private static string Replace(string sIn, string sFind, string sReplace) private static string Replace(string sIn, string sFind, string sReplace)
{ {
@ -458,7 +418,7 @@ namespace InputText
if (FindTag(sLine, sTagName)) if (FindTag(sLine, sTagName))
{ {
string sTagData = TagData(sLine, sTagName); string sTagData = TagData(sLine, sTagName);
// Rainmeter.Log(Rainmeter.LogLevel.Debug, "InputText: Overriding " + sTagName + " with " + sTagData); // API.Log(API.LogType.Debug, "InputText: Overriding " + sTagName + " with " + sTagData);
if (sTagData.StartsWith("\"")) if (sTagData.StartsWith("\""))
Overrides.Add(sTagName, sTagData.Substring(1, sTagData.Length - 2)); Overrides.Add(sTagName, sTagData.Substring(1, sTagData.Length - 2));
else else

View File

@ -94,6 +94,7 @@
<DependentUpon>InputBox.cs</DependentUpon> <DependentUpon>InputBox.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="$(SolutionDir)Version.cs" /> <Compile Include="$(SolutionDir)Version.cs" />
<Compile Include="$(SolutionDir)Plugins\API\RainmeterAPI.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="InputBox.resx"> <EmbeddedResource Include="InputBox.resx">

View File

@ -1,11 +1,27 @@
using System; /*
using System.Collections.Generic; Copyright (C) 2013 Rainmeter Team
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.
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;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using Rainmeter;
// This is a utility class / toolkit for communicating with Rainmeter and managing // This is a utility class / toolkit for communicating with Rainmeter and managing
// logging, INI settings, bangs, window positioning, multiple instances, and temporary // window positioning.
// data storage.
// //
// You should not need to edit this code except to expand the toolkit support. // You should not need to edit this code except to expand the toolkit support.
// //
@ -13,119 +29,78 @@ using System.Threading;
// that you create (such as new forms, classes, and controls). // that you create (such as new forms, classes, and controls).
namespace InputText namespace InputText
{ {
public class WindowWrapper : System.Windows.Forms.IWin32Window public class SkinWindow : System.Windows.Forms.IWin32Window
{ {
public WindowWrapper(IntPtr handle) private string _SkinName;
private IntPtr _Handle;
private int _X = 0;
private int _Y = 0;
private int _W = 0;
private int _H = 0;
private bool _IsTopmost = false;
public SkinWindow(Rainmeter.API rm)
{ {
_hwnd = handle; UpdateStatus(rm);
} }
#region Methods for getting the screen-relative location of the current skin
public IntPtr Handle public IntPtr Handle
{ {
get { return _hwnd; } get { return this._Handle; }
} }
private IntPtr _hwnd; public int X
}
public class Rainmeter
{
#region Methods for getting the screen-relative location of the current skin
public static IntPtr GetConfigWindow(Rainmeter.Settings.InstanceSettings Instance)
{ {
return (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File)))); get { return this._X; }
}
public static int ConfigX(string sSkin)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin)));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Left;
}
public static int ConfigX(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Left;
} }
public static int ConfigY(string sSkin) public int Y
{ {
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin))); get { return this._Y; }
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Top;
}
public static int ConfigY(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Top;
} }
public static int ConfigWidth(string sSkin) public int Width
{ {
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin))); get { return this._W; }
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Right - rct.Left;
}
public static int ConfigWidth(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Right - rct.Left;
} }
public static int ConfigHeight(string sSkin) public int Height
{ {
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", sSkin))); get { return this._H; }
RECT rct;
if (!GetWindowRect(hwnd, out rct))
{
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + sSkin + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
return 0;
}
return rct.Bottom - rct.Top;
} }
public static int ConfigHeight(Rainmeter.Settings.InstanceSettings Instance)
public bool IsTopmost
{ {
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File)))); get { return this._IsTopmost; }
RECT rct; }
if (!GetWindowRect(hwnd, out rct))
public void UpdateStatus(Rainmeter.API rm = null)
{
if (rm != null)
{ {
Rainmeter.Log(LogLevel.Error, "Rainmeter told us the HWND for window '" + Rainmeter.PluginBridge("GetConfig", Instance.INI_File) + "' is " + hwnd.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it"); this._SkinName = rm.GetSkinName();
return 0; this._Handle = rm.GetSkinWindow();
} }
return rct.Bottom - rct.Top;
RECT rct;
if (GetWindowRect(this._Handle, out rct))
{
this._X = rct.Left;
this._Y = rct.Top;
this._W = rct.Right - rct.Left;
this._H = rct.Bottom - rct.Top;
}
else
{
API.Log(API.LogType.Error,
"Rainmeter told us the HWND for window '" + this._SkinName + "' is " + this._Handle.ToInt32().ToString() + "L, but couldn't receive a proper RECT from it");
}
this._IsTopmost = ((GetWindowLong(this._Handle, GWL_EXSTYLE) & WS_EX_TOPMOST) > 0);
} }
#region GetWindowRect() platform invoke to get the size/location of a window #region GetWindowRect() platform invoke to get the size/location of a window
@ -134,12 +109,6 @@ namespace InputText
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
#endregion
#region GetParent() platform invoke to get the handle of a parent window
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetParent(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct RECT public struct RECT
{ {
@ -149,578 +118,15 @@ namespace InputText
public int Bottom; // y position of lower-right corner public int Bottom; // y position of lower-right corner
} }
#endregion #endregion
#region SendMessage -- SendMessage (this variant is only for WM_COPYSTRUCT messages) #region GetWindowLong() -- platform invoke to check a window's Z-order (Topmost=Auto)
[DllImport("user32.dll", CharSet = CharSet.Auto)] [DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); private static extern int GetWindowLong(IntPtr hwnd, int nIndex);
[StructLayout(LayoutKind.Sequential)] private const int GWL_EXSTYLE = -20;
struct COPYDATASTRUCT private const int WS_EX_TOPMOST = 8;
{
public UInt32 dwData;
public int cbData;
public IntPtr lpData;
}
#endregion #endregion
#region FindWindowByClass -- platform invoke to find a window given a class name
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindowByClass(string lpClassName, IntPtr ZeroOnly);
#endregion
#region GetWindowInfo -- platform invoke to check a window's Z-order (Topmost=Auto)
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[StructLayout(LayoutKind.Sequential)]
private struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
// Call this function to determine if the parent skin is topmost
public static bool ParentIsTopmost(Rainmeter.Settings.InstanceSettings Instance)
{
IntPtr hwnd = (IntPtr)(UInt32.Parse(Rainmeter.PluginBridge("GetWindow", Rainmeter.PluginBridge("GetConfig", Instance.INI_File))));
WINDOWINFO info = new WINDOWINFO(true);
GetWindowInfo(hwnd, ref info);
return ((info.dwExStyle & 0x00000008L) > 0);
}
#endregion
#region SkinName -- gets the current skin name
public static string SkinName(Rainmeter.Settings.InstanceSettings Instance)
{
try
{
return Instance.ConfigName;
/*
if (Instance.GetTempValue("_internal_SkinPath", string.Empty).ToString() == string.Empty)
{
string sAppDataPath = System.Environment.GetEnvironmentVariable("AppData").Trim();
string sRainmeterINIText = System.IO.File.ReadAllText(sAppDataPath + "\\Rainmeter\\Rainmeter.ini");
string sSkinPath = Chopper(sRainmeterINIText.Replace('\n', '\r'), "SkinPath=", "\r").Trim().TrimEnd(new char[] { '\\' });
Instance.SetTempValue("_internal_SkinPath", sSkinPath);
}
System.IO.FileInfo fi = new System.IO.FileInfo(Instance.INI_File);
return fi.DirectoryName.Replace(Instance.GetTempValue("_internal_SkinPath", string.Empty).ToString(), string.Empty).TrimEnd(new char[] { '\\' }).TrimStart(new char[] { '\\' });
*/
}
catch { }
return string.Empty;
}
#endregion
#endregion
#region Chopper -- string manipulation
public static string Chopper(string sText, string sSearch, string sEnd, int offset)
{
string sIntermediate = "";
try
{
if ((sSearch == null) || (sSearch == string.Empty))
{
sIntermediate = sText.Substring(offset);
}
else
{
if (sText.Contains(sSearch) == false)
return sText;
sIntermediate = sText.Substring(sText.IndexOf(sSearch) + sSearch.Length + offset);
}
if ((sEnd == null) || (sEnd == string.Empty))
return sIntermediate;
if (sIntermediate.Contains(sEnd) == false)
return sIntermediate;
return sIntermediate.Substring(0, sIntermediate.IndexOf(sEnd));
}
catch
{
if (sIntermediate == "")
return sText;
return sIntermediate;
}
}
public static string Chopper(string sText, string sSearch, string sEnd)
{
return Chopper(sText, sSearch, sEnd, 0);
}
#endregion
#region Version helpers (converts "1.04" or "1, 4" to 1004, etc.)
public static UInt32 Version(double dVersion)
{
return (UInt32)(dVersion * 1000.0);
}
public static UInt32 Version(int iMajor, int iMinor)
{
return (UInt32)((iMajor * 1000) + iMinor);
}
#endregion
#region Converts a C# 'string' to a C++ 'char *'
public static unsafe char* String(string s)
{
fixed (char* p = s) return p;
}
#endregion
#region Export for Rainmeter's new plugin bridge
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe char* PluginBridge(char* sCommand, char* sData);
private unsafe static string PluginBridge(string sCommand, string sData)
{
try
{
return new string(PluginBridge(Rainmeter.String(sCommand), Rainmeter.String(sData)));
}
catch { }
return string.Empty;
}
#endregion
#region Read INI values using Rainmeter's 'ReadConfigString' export
// We have to use this method rather than loading the .INI file manually because Rainmeter will
// replace tokens for us. See: http://rainmeter.net/RainCMS/?q=Settings_BuiltInVariables
//
// Please note that this is done during plugin initialization and stored in the Instance
// variable. This is done automatically, so this function should not be used by plugin developers
// directly, therefore the methods here are 'private'.
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe char* ReadConfigString(char* sSection, char* key, char* defValue);
// If an INI is missing, a blank string will be returned to avoid raising exceptions
private unsafe static string ReadConfigString(string sSection, string sKey)
{
try
{
char* szString = ReadConfigString(Rainmeter.String(sSection), Rainmeter.String(sKey), Rainmeter.String(string.Empty));
if (szString != null)
return new string(szString);
}
catch { }
return string.Empty;
}
#endregion
#region Use Rainmeter's 'LSLog' export to log using its format and settings
[DllImport("Rainmeter.dll", CharSet = CharSet.Auto)]
private extern static unsafe UInt16 LSLog(int nLevel, char* pszModule, char* pszMessage);
public enum LogLevel : int
{
Error = 1,
Warning = 2,
Notice = 3,
Debug = 4
}
// You can call this function directly to log to Rainmeter.log
//
// Rainmeter needs to be configured to allow debug logging, of course.
public static unsafe bool Log(LogLevel level, string sText)
{
return (Rainmeter.LSLog((int)level, Rainmeter.String("C# plugin"), Rainmeter.String(sText)) != 0);
}
#endregion
#region Send a bang to Rainmeter (prepends a '!' if necessary)
public static void Bang(string sBang)
{
System.Diagnostics.Process.Start(System.Windows.Forms.Application.ExecutablePath, sBang);
}
#endregion
#region Settings are automatically created (and set at the top of 'Main.cs'), don't edit here
// WARNING: DO NOT EDIT THIS HERE. Change your author name, version, etc. in 'Main.cs'
public class Settings
{
public string Author = "(unknown)";
public double Version = 0.01;
public string Email = string.Empty;
public string Comments = string.Empty;
public Settings(string _Author, double _Version)
{
this.Author = _Author;
this.Version = _Version;
}
public Settings(string _Author, double _Version, string _Email)
{
this.Author = _Author;
this.Version = _Version;
this.Email = _Email;
}
public Settings(string _Author, double _Version, string _Email, string _Comments)
{
this.Author = _Author;
this.Version = _Version;
this.Email = _Email;
this.Comments = _Comments;
}
public Dictionary<UInt32, InstanceSettings> Instances = new Dictionary<uint, InstanceSettings>();
public List<SectionKey> KeyValues = new List<SectionKey>();
public struct SectionKey
{
public UInt32 id;
public string INI_File;
public string Section;
public string Key;
public string Value;
}
public unsafe void AddInstance(char* iniFile, char* section, UInt32 id)
{
InstanceSettings new_instance = new InstanceSettings();
new_instance.Initialize(this, iniFile, section, id);
this.Instances.Add(id, new_instance);
bool bInSection = false;
foreach (string line in System.IO.File.ReadAllLines(new_instance.INI_File))
{
if (line.Trim().StartsWith(";")) continue; // ignore comments
if (line.Trim().StartsWith("[")) bInSection = false; // new section
// section test
if (line.Trim().ToLower() == ("[" + new_instance.Section.ToLower() + "]"))
bInSection = true;
if (!bInSection) continue; // abort this pass if not in section
if (!line.Contains("=")) continue; // abort this pass if there's no INI setting here
string[] sLineParts = line.Trim().Split(new char[] { '=' });
SectionKey sk = new SectionKey();
sk.id = id;
sk.INI_File = new_instance.INI_File;
sk.Key = sLineParts[0].Trim();
sk.Section = new_instance.Section;
sk.Value = ReadConfigString(new_instance.Section, sLineParts[0].Trim());
this.KeyValues.Add(sk);
}
}
public void RemoveInstance(UInt32 id)
{
try
{
start_over:
for (int i = 0; i < this.KeyValues.Count; i++)
{
if (this.KeyValues[i].id == id)
{
this.KeyValues.RemoveAt(i);
goto start_over; // start over since the IEnumerable has been modified
}
}
this.Instances.Remove(id);
}
catch { }
}
public class InstanceSettings
{
private UInt32 _ID = 0;
private string _INI_File = string.Empty;
private string _Section = string.Empty;
private Settings PluginSettings = null;
private Dictionary<string, object> TempData = new Dictionary<string, object>();
private object locker = new object();
public object GetTempValue(string name, object oDefault)
{
lock (this.locker)
{
if (this.TempData.ContainsKey(name))
return this.TempData[name];
return oDefault;
}
}
public void SetTempValue(string name, object o)
{
lock (this.locker)
{
if (this.TempData.ContainsKey(name))
this.TempData[name] = o;
else
this.TempData.Add(name, o);
}
}
public string INI_Value(string name)
{
try
{
foreach (SectionKey sk in PluginSettings.KeyValues)
if (sk.id == this.ID)
if (sk.Section == this.Section)
if (sk.Key.Trim().ToLower() == name.Trim().ToLower())
return sk.Value;
}
catch { }
return string.Empty;
}
public unsafe void Initialize(Settings _PluginSettings, char* iniFile, char* section, UInt32 id)
{
this.PluginSettings = _PluginSettings;
this._ID = id;
this._INI_File = new string(iniFile);
this._Section = new string(section);
this.ConfigName = Rainmeter.PluginBridge("GetConfig", this.INI_File);
}
public string GetVariable(string sVariable)
{
return Rainmeter.PluginBridge("GetVariable", "\"" + this.ConfigName + "\" " + sVariable.Trim() + "");
}
public string SetVariable(string sVariable, object oData)
{
return Rainmeter.PluginBridge("SetVariable", "\"" + this.ConfigName + "\" " + sVariable.Trim() + " \"" + oData.ToString().Trim() + "\"");
}
public string ConfigName = string.Empty;
public UInt32 ID
{
get
{
return this._ID;
}
set
{
this._ID = value;
}
}
public string INI_File
{
get
{
return this._INI_File;
}
}
public string Section
{
get
{
return this._Section;
}
}
}
}
#endregion
}
public class YourPlugin
{
#region YourPlugin class -- do not modify
// This class is a simple launcher for your actual code in PluginCode.cs
//
// We make use of non-volatile data and threading to let your work run in another
// thread, making Rainmeter nice and responsive. Checks are automatically performed
// so that overlapping of execution does not occur.
// Default values of a blank string for GetUpdate() and zero for Update()/Update2()
// are returned.
public UInt32 Update(Rainmeter.Settings Plugin, UInt32 id)
{
//bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_U_AlreadyRunning", false);
//if (!bAlreadyRunning)
//{
// Plugin.Instances[id].SetTempValue("__RMT_U_AlreadyRunning", true);
// ThreadPool.QueueUserWorkItem(_instance =>
// {
// Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance;
// try
// {
// Instance.SetTempValue("__RMT_U_LastValue", new PluginCode().Update(Instance));
// }
// catch (Exception ex)
// {
// Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in Update(), " + ex.GetType().ToString() + ": " + ex.Message);
// }
// Instance.SetTempValue("__RMT_U_AlreadyRunning", false);
// }, Plugin.Instances[id]);
//}
//try
//{
// return (UInt32)Plugin.Instances[id].GetTempValue("__RMT_U_LastValue", 0);
//}
//catch
{
return 0;
}
}
//public double Update2(Rainmeter.Settings Plugin, UInt32 id)
//{
// bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_U2_AlreadyRunning", false);
// if (!bAlreadyRunning)
// {
// Plugin.Instances[id].SetTempValue("__RMT_U2_AlreadyRunning", true);
// ThreadPool.QueueUserWorkItem(_instance =>
// {
// Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance;
// try
// {
// Instance.SetTempValue("__RMT_U2_LastValue", new PluginCode().Update2(Instance));
// }
// catch (Exception ex)
// {
// Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in Update2(), " + ex.GetType().ToString() + ": " + ex.Message);
// }
// Instance.SetTempValue("__RMT_U2_AlreadyRunning", false);
// }, Plugin.Instances[id]);
// }
// try
// {
// return (double)Plugin.Instances[id].GetTempValue("__RMT_U2_LastValue", 0.0);
// }
// catch
// {
// return 0.0;
// }
//}
public string GetString(Rainmeter.Settings Plugin, UInt32 id)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_GS_AlreadyRunning", false);
if (!bAlreadyRunning)
{
Plugin.Instances[id].SetTempValue("__RMT_GS_AlreadyRunning", true);
ThreadPool.QueueUserWorkItem(_instance =>
{
Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)_instance;
try
{
Instance.SetTempValue("__RMT_GS_LastValue", new PluginCode().GetString(Instance));
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in GetString(), " + ex.GetType().ToString() + ": " + ex.Message);
}
Instance.SetTempValue("__RMT_GS_AlreadyRunning", false);
}, Plugin.Instances[id]);
}
try
{
return (string)Plugin.Instances[id].GetTempValue("__RMT_GS_LastValue", string.Empty);
}
catch
{
return string.Empty;
}
}
public void ExecuteBang(Rainmeter.Settings Plugin, UInt32 id, string sArguments)
{
bool bAlreadyRunning = (bool)Plugin.Instances[id].GetTempValue("__RMT_EB_AlreadyRunning", false);
if (!bAlreadyRunning)
{
Plugin.Instances[id].SetTempValue("__RMT_EB_AlreadyRunning", true);
ThreadPool.QueueUserWorkItem(_param =>
{
Rainmeter.Settings.InstanceSettings Instance = (Rainmeter.Settings.InstanceSettings)((ExecuteBangParam)_param).Instance;
string Command = (string)((ExecuteBangParam)_param).Command;
try
{
new PluginCode().ExecuteBang(Instance, Command);
}
catch (Exception ex)
{
Rainmeter.Log(Rainmeter.LogLevel.Error, "C# plugin in ExecuteBang(), " + ex.GetType().ToString() + ": " + ex.Message);
}
Instance.SetTempValue("__RMT_EB_AlreadyRunning", false);
}, new ExecuteBangParam(Plugin.Instances[id], sArguments));
}
return;
}
private class ExecuteBangParam
{
public Rainmeter.Settings.InstanceSettings Instance = null;
public string Command = string.Empty;
public ExecuteBangParam(Rainmeter.Settings.InstanceSettings _Instance, string _Command)
{
this.Instance = _Instance;
this.Command = _Command;
}
}
#endregion #endregion
} }