C# Plugin Overview


When making a Rainmeter plugin there are a some basic functions that your code must export, as well as several optional ones you may want to export.

A copy of the API with some examples can be found here as well as the basics of each function listed below:

Required functions

Initialize void Initialize(ref IntPtr data, IntPtr rm)

Called when a measure is created (i.e. when a skin is loaded or when a skin is refreshed). Create your measure object here. Any other initialization or code that only needs to happen once should be placed here.

  • data : You may allocate and store measure specific data to this variable. The object you save here will be passed to other functions below.
  • rm : Internal pointer that is passed to most API functions. If needed, you may save this value for later use (like for logging functions).

Example:

[DllExport]
public static void Initialize(ref IntPtr data, IntPtr rm)
{
Measure measure = new Measure();
data = GCHandle.ToIntPtr(GCHandle.Alloc(measure));
Rainmeter.API api = (Rainmeter.API)rm;
// Do any initialization here, saving any values you want to into data for later
}
Reload void Reload(IntPtr data, IntPtr rm, ref double maxValue)

Called by Rainmeter when the measure settings are to be read directly after Initialize. If DynamicVariables=1 is set on the measure, this function is called just before every call to the Update function during the update cycle.

  • data : Pointer to the data set in Initialize.
  • rm : Internal pointer that is passed to most API functions.
  • maxValue : Pointer to a double that can be assigned to the default maximum value for this measure. A value of 0.0 will make it based on the highest value returned from the Update function. Do not set maxValue unless necessary.

Example:

[DllExport]
public static void Reload(IntPtr data, IntPtr rm, ref double maxValue)
{
Measure measure = (Measure)data;
// Read measures values from the measure (see API functions)

// The expected value returned in the Update function will not exceed 100.0
maxValue = 100.0;
}
Update double Update(IntPtr data)

Called by Rainmeter when a measure value is to be updated (i.e. on each update cycle). The number returned represents the number value of the measure.

Returns: The number value of the measure (as a double). This value will be used as the string value of the measure if the GetString function is not used or returns a null.

Example:

[DllExport]
public static double Update(IntPtr data)
{
Measure measure = (Measure)data;
//Any processing that needs to happen during the update cycle should happen here
return 0.0; //return whatever value you want rainmeter to display here
}
Finalize void Finalize(IntPtr data)

Called by Rainmeter when a measure is about to be destroyed. Perform cleanup here.

Example:

[DllExport]
public static void Finalize(IntPtr data)
{
Measure measure = (Measure)data;
// Do any cleanup here
GCHandle.FromIntPtr(data).Free();
}

Optional functions

GetString IntPtr GetString(IntPtr data)

Optional function that returns the string value of the measure. Since this function is called 'on-demand' and may be called multiple times during the update cycle, do not process any data or consume CPU in this function. Do as minimal processing as possible to return the desired string. It is recommended to do all processing during the Update function and set a string variable there and retrieve that string variable in this function. The return value must be marshalled from a C# style string to a C style string (WCHAR*).

Returns: The string value for the measure. If you want the number value (returned from Update) to be used as the measures value, return null instead. The return value must be marshalled.

Example:

[DllExport]
public static IntPtr GetString(IntPtr data)
{
Measure measure = (Measure)data;
if (something)
{
// Return a string value to use for this measure (must be marshalled)
return Marshal.StringToHGlobalUni("SomeValue");
}

// Return null when you want to use the number
// value for this measure (the value returned from the Update function)
return IntPtr.Zero;
}
ExecuteBang void ExecuteBang(IntPtr data, string args)

Optional function that will process a custom bang when called from !CommandMeasure. This can be used to change some data within the measure, or to interact with another application.

  • data : Pointer to the data set in Initialize.
  • args : String that contains any arguments to parse. args is a LPCWSTR in C++ and must be marshalled to a C# style string.

Example:

[DllExport]
public static void ExecuteBang(IntPtr data, [MarshalAs(UnmanagedType.LPWStr)] string args)
{
Measure measure = (Measure)data;
// !CommandMeasure was used on this measure...any arguments will be in args
}
Custom function string func(IntPtr data, const int argc, const string[] argv)

You can define a custom function to be used in a section variable. The name of the function is the name to be used in the skin file as a section variable. The function must be exported and the function prototype must be: string func(IntPtr data, const int argc, const string[] argv).

The function name can be anything except the following: Initialize, Reload, Update, Finialize, GetString, ExecuteBang, Update2, GetPluginAuthor, and GetPluginVersion.

The skin will call this function (as a section variable) like this: [PluginMeasure:func(someArg1, someArg2)].

  • data : Pointer to the data set in Initialize.
  • argc : Number of arguments passed to the function.
  • argv : Arguments passed to the function as an array of strings. argv is an array of strings (LPCWSTR) in C++ and must be marshalled to a C# style string.

Returns: A string to replace the section variable with. If a null is returned, the variable will not be replaced and remain unchanged. The return value must be marshalled.

Example:

[DllExport]
public static IntPtr ToLower(IntPtr data, const int argc,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] const string[] argv)
{
Measure measure = (Measure)data;
if (argc > 0)
{
// Do something and return a value to replace variable with (must be marshalled)
return Marshal.StringToHGlobalUni(doSomething(argv));
}

return IntPtr.Zero; // Do not replace the variable
}