It is currently November 21st, 2019, 10:17 am

Unable to log

Share and get help with Plugins and Addons
ShavedJesus
Posts: 10
Joined: October 19th, 2019, 1:35 pm

Unable to log

ShavedJesus » October 19th, 2019, 1:59 pm

Hello everyone,

I tried to search on the forum but didn't find nothing about and for me the documentation is not so clear.
I'm trying to send a couple of messages in the RM logs in order to debug, but it doesn't work. Where am I wrong?

I tried on both "Initialize" and "Update" but nothing shows up in RM logs.

Thank you very much in advance!

Code: Select all

[DllExport]

	class Measure
    {
        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 Rainmeter.API api;
    }

	/* ... */

        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;

            measure.api = api;

            measure.api.Log(API.LogType.Notice, "AAA: " + TaskbarHandle.ToString());
            measure.api.Log(API.LogType.Notice, "BBB: " + SecondaryTaskbar.ToString());
        }

        [DllExport]
        public static double Update(IntPtr data)
        {
            Measure measure = (Measure)data;

            measure.api.Log(API.LogType.Notice, "AAA: " + TaskbarHandle.ToString());
            measure.api.Log(API.LogType.Notice, "BBB: " + SecondaryTaskbar.ToString());

            AccentPolicy accentPolicy = new AccentPolicy();
            accentPolicy.AccentState = measure.inputStr == null ? (AccentState)2 : (AccentState)Int32.Parse(measure.inputStr);

            EnableBlur(TaskbarHandle, accentPolicy);
            EnableBlur(SecondaryTaskbar, accentPolicy);

            return 0.0;
        }
        
      	/* ... */
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 2:10 pm

You need to be sure that you are carrying the "rm" part of the structure through to all the places you want to use it. Take a look at this:

Code: Select all

struct Measure
{
	void* rm;
	Measure():
	rm()
	{}
};

PLUGIN_EXPORT void Initialize(void** data, void* rm)
{
	Measure* measure = new Measure;
	measure->rm = rm;
	*data = measure;
	
	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice' in Initalize()");		
}

PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
	Measure* measure = (Measure*)data;
	
	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice' in Reload()");	
}

PLUGIN_EXPORT double Update(void* data)
{
	Measure* measure = (Measure*)data;

	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice'in Update");
	return 0.0;
}
See if that is any help. I'm no expert on C++, and Brian may want to weigh in when he comes around later today, but this might get you started.
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 2:24 pm

Here is a full example...

Code: Select all

#include <Windows.h>
#include <string>
#include "../../API/RainmeterAPI.h"

struct Measure
{
	std::wstring strValue;
	void* rm;
	Measure():
		strValue(),
		rm()
	{}
};

PLUGIN_EXPORT void Initialize(void** data, void* rm)
{
	Measure* measure = new Measure;
	measure->rm = rm;
	*data = measure;
	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice' in Initalize()");		
}

PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
	Measure* measure = (Measure*)data;
	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice' in Reload()");		
}

PLUGIN_EXPORT double Update(void* data)
{
	Measure* measure = (Measure*)data;

	HWND hwnd = GetForegroundWindow(); // get handle of currently active window

	const int length = GetWindowTextLength(hwnd);
	std::wstring wndTitle;
	wndTitle.resize(length + 1);
	GetWindowText(hwnd, &wndTitle[0], (int)wndTitle.size());
	measure->strValue = wndTitle;
	RmLog(measure->rm, LOG_NOTICE, L"I am a 'notice'in Update");
	return length;
}

PLUGIN_EXPORT LPCWSTR GetString(void* data)
{
	Measure* measure = (Measure*)data;
	return measure->strValue.c_str();
}

//PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
//{
//	Measure* measure = (Measure*)data;
//}

//PLUGIN_EXPORT LPCWSTR (void* data, const int argc, const WCHAR* argv[])
//{
//	Measure* measure = (Measure*)data;
//	return nullptr;
//}

PLUGIN_EXPORT void Finalize(void* data)
{
	Measure* measure = (Measure*)data;
	delete measure;
}

1.jpg

In general, you won't ever want to log anything, or in fact DO anything in GetString(), as that is executed every time the string value is asked for, by any and all measures or meters in the skin, and will tend to run amok if you do things there. Do the work in Update() and just return any string set by that in GetString().
You do not have the required permissions to view the files attached to this post.
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 2:40 pm

Oh crap. Your code is C#, not C++... Hopefully what I did still points you in the right direction.
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 2:43 pm

Here is a C# example that does some logging...

Code: Select all

using Rainmeter;
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace PluginImageSize
{
    class Measure
    {
        static public implicit operator Measure(IntPtr data)
        {
            return (Measure)GCHandle.FromIntPtr(data).Target;
        }
        public IntPtr buffer = IntPtr.Zero;
        public IntPtr rm = IntPtr.Zero;

        public double width, height;
        public Bitmap ImageBitmap;
        public string ImageName;
        public string Dimension;
        public bool fileErrorShown = false;
        public bool dimErrorShown = false;
    }

    public class Plugin
    {
        [DllExport]
        public static void Initialize(ref IntPtr data, IntPtr rm)
        {
            data = GCHandle.ToIntPtr(GCHandle.Alloc(new Measure()));
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)rm;
            measure.rm = rm;
        }

        [DllExport]
        public static void Reload(IntPtr data, IntPtr rm, ref double maxValue)
        {
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)rm;

            measure.width = 0.0;
            measure.height = 0.0;

            measure.ImageName = api.ReadString("ImageName", "");
            measure.Dimension = api.ReadString("Dimension", "WIDTH").ToUpper();

            int isDisabled = api.ReadInt("Disabled", 0);
            int isPaused = api.ReadInt("Paused", 0);

            if (isDisabled == 0 && isPaused == 0)
            {
                try
                {
                    measure.ImageBitmap = new Bitmap(@measure.ImageName, true);
                    measure.width = measure.ImageBitmap.Width;
                    measure.height = measure.ImageBitmap.Height;
                    measure.ImageBitmap.Dispose();
                    measure.fileErrorShown = false;
                }
                catch
                {
                    if (!measure.fileErrorShown)
                    {
                        api.Log(API.LogType.Error, "ImageSize.dll: File error for " + measure.ImageName);
                        measure.fileErrorShown = true;
                    }
                }
            }
        }

        [DllExport]
        public static double Update(IntPtr data)
        {
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)measure.rm;

            if (measure.Dimension == "WIDTH")
            {
                measure.dimErrorShown = false;
                return measure.width;
            }
            else if (measure.Dimension == "HEIGHT")
            {
                measure.dimErrorShown = false;
                return measure.height;
            }
            else
            {
                if (!measure.dimErrorShown)
                {
                    api.Log(API.LogType.Error, "ImageSize.dll: Dimension option " + measure.Dimension + " invalid");
                    measure.dimErrorShown = true;
                }
                return 0.0;
            }

        }

        [DllExport]
        public static void Finalize(IntPtr data)
        {
            Measure measure = (Measure)data;
            if (measure.buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(measure.buffer);
            }
            GCHandle.FromIntPtr(data).Free();
        }
    }
}
ShavedJesus
Posts: 10
Joined: October 19th, 2019, 1:35 pm

Re: Unable to log

ShavedJesus » October 19th, 2019, 3:07 pm

Hello jsmorley.

Thank you very much for your answer.
Unfortunately I'm trying to keep the rm reference across the API functions, but I cannot figure it out.

I don't see anything wrong actually, I also tried to remove the skin and load it again completely because I was wondering about other issues.

Now I'm saving references to both API and RM pointers:

Code: Select all

class Measure
    {
        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
        [b]public Rainmeter.API api;
        public IntPtr rm = IntPtr.Zero;[/b]
    }
I save them in the Initialize function:

Code: Select all

	[DllExport]
        public static void Initialize(ref IntPtr data, IntPtr [b]rm[/b])
        {
            data = GCHandle.ToIntPtr(GCHandle.Alloc(new Measure()));
            Measure measure = new Measure();
            [b]Rainmeter.API api = (Rainmeter.API)rm;[/b]
            [b]measure.api = api;
            measure.rm = rm;[/b]
        }
and then try to log in the update as I see in your example:

Code: Select all

	[DllExport]
        public static double Update(IntPtr data)
        {
            Measure measure = (Measure)data;
            
            measure.api.Log(API.LogType.Notice, "AAA: " + TaskbarHandle.ToString());
            measure.api.Log(API.LogType.Notice, "BBB: " + SecondaryTaskbar.ToString());

            AccentPolicy accentPolicy = new AccentPolicy();
            accentPolicy.AccentState = measure.inputStr == null ? (AccentState)2 : (AccentState)Int32.Parse(measure.inputStr);

            EnableBlur(TaskbarHandle, accentPolicy);
            EnableBlur(SecondaryTaskbar, accentPolicy);

            return 0.0;
        }
Still nothing happens. I don't understand what I'm doing wrong.




jsmorley wrote:
October 19th, 2019, 2:43 pm
Here is a C# example that does some logging...

Code: Select all

using Rainmeter;
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace PluginImageSize
{
    class Measure
    {
        static public implicit operator Measure(IntPtr data)
        {
            return (Measure)GCHandle.FromIntPtr(data).Target;
        }
        public IntPtr buffer = IntPtr.Zero;
        public IntPtr rm = IntPtr.Zero;

        public double width, height;
        public Bitmap ImageBitmap;
        public string ImageName;
        public string Dimension;
        public bool fileErrorShown = false;
        public bool dimErrorShown = false;
    }

    public class Plugin
    {
        [DllExport]
        public static void Initialize(ref IntPtr data, IntPtr rm)
        {
            data = GCHandle.ToIntPtr(GCHandle.Alloc(new Measure()));
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)rm;
            measure.rm = rm;
        }

        [DllExport]
        public static void Reload(IntPtr data, IntPtr rm, ref double maxValue)
        {
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)rm;

            measure.width = 0.0;
            measure.height = 0.0;

            measure.ImageName = api.ReadString("ImageName", "");
            measure.Dimension = api.ReadString("Dimension", "WIDTH").ToUpper();

            int isDisabled = api.ReadInt("Disabled", 0);
            int isPaused = api.ReadInt("Paused", 0);

            if (isDisabled == 0 && isPaused == 0)
            {
                try
                {
                    measure.ImageBitmap = new Bitmap(@measure.ImageName, true);
                    measure.width = measure.ImageBitmap.Width;
                    measure.height = measure.ImageBitmap.Height;
                    measure.ImageBitmap.Dispose();
                    measure.fileErrorShown = false;
                }
                catch
                {
                    if (!measure.fileErrorShown)
                    {
                        api.Log(API.LogType.Error, "ImageSize.dll: File error for " + measure.ImageName);
                        measure.fileErrorShown = true;
                    }
                }
            }
        }

        [DllExport]
        public static double Update(IntPtr data)
        {
            Measure measure = (Measure)data;
            Rainmeter.API api = (Rainmeter.API)measure.rm;

            if (measure.Dimension == "WIDTH")
            {
                measure.dimErrorShown = false;
                return measure.width;
            }
            else if (measure.Dimension == "HEIGHT")
            {
                measure.dimErrorShown = false;
                return measure.height;
            }
            else
            {
                if (!measure.dimErrorShown)
                {
                    api.Log(API.LogType.Error, "ImageSize.dll: Dimension option " + measure.Dimension + " invalid");
                    measure.dimErrorShown = true;
                }
                return 0.0;
            }

        }

        [DllExport]
        public static void Finalize(IntPtr data)
        {
            Measure measure = (Measure)data;
            if (measure.buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(measure.buffer);
            }
            GCHandle.FromIntPtr(data).Free();
        }
    }
}
ShavedJesus
Posts: 10
Joined: October 19th, 2019, 1:35 pm

Re: Unable to log

ShavedJesus » October 19th, 2019, 3:18 pm

Am I doing something wrong with the references?

I actually have my project with one .cs file and I included the RainmeterAPI.cs into it and compiled togheter. Then I placed the .dll in "c:\users\username\roaming\rainmeter\plugins"

Is it correct?

thank you very much.
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 3:23 pm

ShavedJesus wrote:
October 19th, 2019, 3:18 pm
Am I doing something wrong with the references?

I actually have my project with one .cs file and I included the RainmeterAPI.cs into it and compiled togheter. Then I placed the .dll in "c:\users\username\roaming\rainmeter\plugins"

Is it correct?

thank you very much.
I would download the plugin SDK

https://github.com/rainmeter/rainmeter-plugin-sdk

And create a structure something like this:


1.jpg
2.jpg
3.jpg
3.1.jpg
4.jpg
5.jpg


Then when you "build" the 32bit and 64bit versions of the plugin .dll, put the correct one for your system in

C:\Users\YourName\AppData\Roaming\Rainmeter\Plugins
You do not have the required permissions to view the files attached to this post.
ShavedJesus
Posts: 10
Joined: October 19th, 2019, 1:35 pm

Re: Unable to log

ShavedJesus » October 19th, 2019, 4:14 pm

Got it!
It was something in the project. Thank you very much!

But I don't understand why the SDK solution is still pointing to the old .NET framework 2.0

Thank you anyway!
jsmorley wrote:
October 19th, 2019, 3:23 pm
I would download the plugin SDK

https://github.com/rainmeter/rainmeter-plugin-sdk

And create a structure something like this:



1.jpg

2.jpg

3.jpg

3.1.jpg

4.jpg

5.jpg



Then when you "build" the 32bit and 64bit versions of the plugin .dll, put the correct one for your system in

C:\Users\YourName\AppData\Roaming\Rainmeter\Plugins
User avatar
jsmorley
Developer
Posts: 19743
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Unable to log

jsmorley » October 19th, 2019, 4:40 pm

The "minimum" we need for Rainmeter, mostly for the InputText plugin, is .NET 2.0. Feel free to target any version you like, but do be aware that you probably want to support Windows 7 with the platform updates, so I wouldn't go too far with it. Windows 7 is .NET 3.5.1 I believe. Many people will have updated further than that, but you can't be sure of it.

At the end of the day it's up to you. It's your plugin. Target v4.8 if you want, and then just make Windows 10 a requirement.

I use:

<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

In a couple of my C# plugins.

I believe the currently supported values are v2.0, v3.0, v3.5, v4.5.2, v4.6, v4.6.1, v4.6.2, v4.7, v4.7.1, v4.7.2, and v4.8