Developers


This page is intended for people who want to work with the source code for Rainmeter. This can be to make or suggest changes to the project C++ source code, or to create plugins for Rainmeter in C++ or C#. In addition, there is information on interacting with Rainmeter from external applications.

Note: Documentation for creating or modifying skins in Rainmeter can be found at Rainmeter Documentation.

The Rainmeter project is primarily written in C++ using Microsoft Visual Studio 2019. In addition, custom plugins can be written and distributed separately from the official Rainmeter project using C++ or C#. This page assumes familiarity with Visual Studio and either C++ or C#.

Project Source Code

The source code for the Rainmeter project is maintained at Rainmeter Repository on GitHub.

If you simply wish to obtain the source code to examine it or make a local change to how something works for your own use, you can simply download a .zip file from Download ZIP.

The only software you will need is Microsoft Visual Studio 2019 or the free Microsoft Visual Community which can be obtained at Download Visual Studio. Be sure to download and apply any Visual Studio Updates when prompted.

Create a folder containing the project code from the .zip file, and open Rainmeter.sln in Visual Studio. You can then set the desired Solution Configuration and Solution Platforms fields and build the solution to create Debug or Release versions in x32 or x64 architectures.

Creating a Project Repository

To do any serious work on the project source code, or to get involved in the development of Rainmeter, you will want to create a local repository and install a couple of tools to help manage your copy of the project.

First, you will want to install a local copy of the Git version control software on your PC. This can be obtained from Download Git.

Then, unless you are a fan of the Windows cmd.exe command line, it can be useful to install a Windows front-end client to help manage your Git repositories. There are several options for that, two of the more popular are TortoiseGit for Windows and GitHub Desktop.

To create your repository of the project code, first create an account on GitHub.com. Then from the Rainmeter Repository on GitHub you can fork the project to your account. Now you can use either the Git command line or the Windows front-end client you installed to clone the repository from your personal fork of the project on GitHub to a folder on your PC.

Submitting Code Changes

If you make changes to the project source code that you would like to suggest as changes to the official build, you can make the changes in your personal GitHub repository, then at the Rainmeter repository, create a pull request with your code changes. It will expedite things if you contact the Rainmeter Team either on the forums at Bugs and Feature Suggestions or on IRC at #Rainmeter on Libera.Chat to discuss the desired changes.

Creating a Full Rainmeter Build

In order to create a full build of the Rainmeter installer, you will need one additional piece of software.

Get and install NSIS version 3.04 or later from NSIS Scriptable Install System software on your PC.

Now you can simply run the Build.bat batch file in the Build folder of your local repository. If there are any "not found" errors when you run the batch file, check the paths in the Set commands at the top of the file.

Use Build.bat RELEASE to build a non-beta installer.

To digitally sign the installer and the Rainmeter executables, obtain a certificate from a service that provides them, and create a Certificate.bat file alongside Build.bat with the following contents:

set CERTFILE=/path/to/PFXcert.p12
set CERTKEY=certpassword

Creating Rainmeter Plugins

Anyone can create and distribute custom plugins for Rainmeter.

Note: The Rainmeter Skin Installer program, which is used by end-users to install the skins containing your plugin, will not allow the same or older version of the plugin to overwrite a newer version. The means that it is critically important that every release of your plugin must have the "File version" number incremented. If you don't do this, your plugin will not be distributed.

The only software you will need is Microsoft Visual Studio 2019 or the free Microsoft Visual Community which can be obtained at Download Visual Studio. Be sure to download and apply any Visual Studio Updates when prompted.

Then you will want to download the Rainmeter Plugin SDK to a folder on your PC. The SDK contains the API code needed to create plugins, as well as some starting and sample plugin code for C++ and C#:

  • PluginEmpty
    An empty plugin template you can use as a starting point for your code.
  • PluginSystemVersion
    An example plugin that returns the Windows system version to a skin.
  • PluginParentChild
    An example plugin demonstrating how to do "parent-child" functions in your plugin.
  • PluginSectionVariables
    An example plugin demonstrating how to implement functions to use as section variables in your plugin.

To create a plugin, the simplest approach is to make a copy of and rename the PluginEmpty example folder and files. Use GuidGen.exe from Visual Studio with Format 4 to generate a new GUID and add this and other appropriate changes to the .vcxproj or .csproj files. Open either SDK-CPP.sln (C++) or SDK-CS.sln (C#) in Visual Studio, add your new plugin project to the solution, develop your code in this template and build your plugin. Be sure that you use the Solution Configuration and Solution Platforms fields and build both x32 and x64 architecture release versions of your plugin .dll before you distribute it.

Plugin API Documentation

  • Documentation for C++ plugins can be found here and the API here.
  • Documentation for C# plugins can be found here and the API here.

Using SendMessage with External Applications

The Rainmeter window message API can be used to query or control Rainmeter from external applications. Documentation for the available queriese, as well as their definitions, can be found here.

The examples are for C++ and AutoIt, but similar functionality is available from any programming platform that can send window messages to running applications.

Query

The following sample demonstrates how to retrieve a running skin's window handle based on the skin config name. Note that the returned handle should only be used to check if the skin is active or not -- do not abuse the handle.

C/C++ code:

// Usage: GetSkinWindow(L"illustro\\Clock");
// Return value will be NULL if config not found or a valid HWND otherwise
#include <Windows.h>

HWND GetSkinWindow(const WCHAR* configName)
{
HWND trayWnd = FindWindow(L"RainmeterTrayClass", NULL);
if (trayWnd)
{
COPYDATASTRUCT cds;
cds.dwData = 5101;
cds.cbData = (DWORD)(wcslen(configName) + 1) * sizeof(WCHAR);
cds.lpData = (void*)configName;
return (HWND)SendMessage(trayWnd, WM_COPYDATA, 0, (LPARAM)&cds);
}

return NULL;
}

AutoIT code:

; Usage: $Return = GetSkinWindow("ConfigName")
; Return value will be 0 if config not found
#include <SendMessage.au3>

Func GetSkinWindow($szConfigName)
Local Const $hWnd = WinGetHandle("[CLASS:RainmeterTrayClass]")
If $hWnd <> 0 Then
Local Const $iSize = StringLen($szConfigName) + 1

Local Const $pMem = DllStructCreate("wchar[" & $iSize & "]")
DllStructSetData($pMem, 1, $szConfigName)

Local Const $pCds = DllStructCreate("dword;dword;ptr")
DllStructSetData($pCds, 1, 5101)
DllStructSetData($pCds, 2, ($iSize * 2))
DllStructSetData($pCds, 3, DllStructGetPtr($pMem))

Local Const $WM_COPYDATA = 0x004A
Return _SendMessage($hWnd, $WM_COPYDATA, 0, DllStructGetPtr($pCds))
EndIf

Return 0
EndFunc

The following code demonstrates how to retrieve important application path information for Rainmeter from your external application.

AutoIT code:

#include <SendMessage.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

$RAINMETER_QUERY_WINDOW = WinGetHandle("[CLASS:RainmeterTrayClass]")
$WM_QUERY_RAINMETER = $WM_APP + 1000
$RAINMETER_QUERY_ID_SKINS_PATH = 4101
$RAINMETER_QUERY_ID_SETTINGS_PATH = 4102
$RAINMETER_QUERY_ID_PROGRAM_PATH = 4104
$RAINMETER_QUERY_ID_CONFIG_EDITOR = 4106
$WM_QUERY_RAINMETER_RETURN = ""

Dim $PathsArray[4]

$hGUI = GUICreate("", 1, 1, -1, -1)

If Not ProcessExists("Rainmeter.exe") Then
MsgBox(16, "GetPath Error", "Rainmeter must be running to use GetPath.")
Exit
EndIf

GUIRegisterMsg($WM_COPYDATA, "_ReadMessage")

_SendMessage($RAINMETER_QUERY_WINDOW, $WM_QUERY_RAINMETER, $RAINMETER_QUERY_ID_PROGRAM_PATH, $hGUI)
$PathsArray[0] = $WM_QUERY_RAINMETER_RETURN

_SendMessage($RAINMETER_QUERY_WINDOW, $WM_QUERY_RAINMETER, $RAINMETER_QUERY_ID_SETTINGS_PATH, $hGUI)
$PathsArray[1] = $WM_QUERY_RAINMETER_RETURN

_SendMessage($RAINMETER_QUERY_WINDOW, $WM_QUERY_RAINMETER, $RAINMETER_QUERY_ID_SKINS_PATH, $hGUI)
$PathsArray[2] = $WM_QUERY_RAINMETER_RETURN

_SendMessage($RAINMETER_QUERY_WINDOW, $WM_QUERY_RAINMETER, $RAINMETER_QUERY_ID_CONFIG_EDITOR, $hGUI)
$PathsArray[3] = $WM_QUERY_RAINMETER_RETURN

_ArrayDisplay($PathsArray)


Func _ReadMessage($hWnd, $uiMsg, $wParam, $lParam)

$pCds = DllStructCreate("dword;dword;ptr", $lParam)
$pData = DllStructGetData($pCds, 3)
$pMem = DllStructCreate("wchar[" & DllStructGetData($pCds, 2) & "]", DllStructGetData($pCds, 3))
$WM_QUERY_RAINMETER_RETURN = DllStructGetData($pMem, 1)

EndFunc ;_ReadMessage

Bangs

The following samples demonstrate how external applications can send bangs to Rainmeter.

C/C++ code:

// Usage: SendBang(L"[!About]");
#include <Windows.h>

void SendBang(const WCHAR* bang)
{
HWND rmWnd = FindWindow(L"DummyRainWClass", NULL);
if (rmWnd)
{
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = (DWORD)(wcslen(bang) + 1) * sizeof(WCHAR);
cds.lpData = (void*)bang;

// Send bang to the Rainmeter window
SendMessage(rmWnd, WM_COPYDATA, 0, (LPARAM)&cds);
}
}

AutoIT code:

; Usage: SendBang("[!About]")
#include <SendMessage.au3>

Func SendBang($szBang)
Local Const $hWnd = WinGetHandle("[CLASS:DummyRainWClass]")
If $hWnd <> 0 Then
Local Const $iSize = StringLen($szBang) + 1

Local Const $pMem = DllStructCreate("wchar[" & $iSize & "]")
DllStructSetData($pMem, 1, $szBang)

Local Const $pCds = DllStructCreate("dword;dword;ptr")
DllStructSetData($pCds, 1, 1)
DllStructSetData($pCds, 2, ($iSize * 2))
DllStructSetData($pCds, 3, DllStructGetPtr($pMem))

Local Const $WM_COPYDATA = 0x004A
_SendMessage($hWnd, $WM_COPYDATA, 0, DllStructGetPtr($pCds))
EndIf
EndFunc