It is currently March 28th, 2024, 2:03 pm

[Work in Progress] Drag&Drop trash plugin for recycle bin

Share and get help with Plugins and Addons
Post Reply
gafusss
Posts: 2
Joined: September 27th, 2014, 1:48 pm

[Work in Progress] Drag&Drop trash plugin for recycle bin

Post by gafusss »

(Sorry if in the wrong section of the forum)

So I really like the idea of rainmeter recycle bin skins, but without drag and drop it's not that useful. I didn't want to use any external tools to implement it, so I decided to write a plugin.
As mentioned, it's a work in progress, so I'll only post the code.
It works for me for quite some time, but sometimes (rarely as of now so can't even catch it, quite often before) when I close the recycle bin skin rainmeter crashes, and I can't figure out when and why that happens.

Code in C++ (VS 2013) (includes poor coding, e.g. calling Rm* functions outside of initialize and reload):

Code: Select all

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

struct Measure
{
	Measure() {}
};

LRESULT CALLBACK DragWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

LONG_PTR DefaultWndProc = NULL;
HWND SkinHWND = NULL;
bool confirm = false;
void* grm = NULL;

PLUGIN_EXPORT void Initialize(void** data, void* rm)
{
	Measure* measure = new Measure;
	*data = measure;

	grm = rm;
	/*LPCWSTR confirmOpt = RmReadString(rm, L"Confirm", L"FALSE");
	if (_wcsicmp(confirmOpt, L"TRUE") == 0)
	{
	confirm = true;
	}
	RmLogF(rm, LOG_DEBUG, L"confirmOpt == %ls, confirm == %ls (INIT)", confirmOpt, confirm ? L"true" : L"false");*/

	SkinHWND = RmGetSkinWindow(rm);
	RmLogF(rm, LOG_DEBUG, L"HWND == %x (INIT)", SkinHWND);

	if (SkinHWND)
	{
		if (DefaultWndProc = GetWindowLongPtr(SkinHWND, GWLP_WNDPROC))
		{
			RmLogF(rm, LOG_DEBUG, L"DefaultWndProc == %x (INIT)", DefaultWndProc);
			SetWindowLongPtr(SkinHWND, GWLP_WNDPROC, (LONG_PTR)DragWndProc);
		}

		DragAcceptFiles(SkinHWND, true);
		RmLogF(rm, LOG_DEBUG, L"Set DragAcceptFiles to TRUE (INIT)");
	}

	RmLogF(rm, LOG_DEBUG, L"D&D: Initialization completed");
}

PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
	Measure* measure = (Measure*)data;

	LPCWSTR confirmOpt = RmReadString(rm, L"Confirm", L"FALSE");
	if (_wcsicmp(confirmOpt, L"TRUE") == 0)
	{
		confirm = true;
	}
	RmLogF(rm, LOG_DEBUG, L"confirmOpt == %ls, confirm == %ls (RELOAD)", confirmOpt, confirm ? L"true" : L"false");

	RmLogF(rm, LOG_DEBUG, L"D&D: Reload completed");
}

LRESULT CALLBACK DragWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (uMsg == WM_DROPFILES)
	{
		RmLog(LOG_DEBUG, L"D&D: Got WM_DROPFILES message (DragWndProc)");
		UINT FileCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0); //If iFile == 0xFFFFFFFF returns number of files 

		if (FileCount)
		{
			SHFILEOPSTRUCT ToDelete;
			ToDelete.hwnd = SkinHWND;
			ToDelete.wFunc = FO_DELETE;
			ToDelete.pTo = NULL;
			ToDelete.fFlags = FOF_ALLOWUNDO;
			if (!confirm)
			{
				ToDelete.fFlags |= FOF_NOCONFIRMATION | FOF_SILENT;
			}

			ToDelete.pFrom = (LPTSTR)malloc(sizeof(WCHAR) * 1);
			UINT CurSize = 1;
			LPTSTR buffer = (LPTSTR)malloc(sizeof(WCHAR)* (MAX_PATH + 1));
			for (UINT i = 0; i < FileCount; i++)
			{
				UINT ReqSize = DragQueryFile((HDROP)wParam, i, buffer, (MAX_PATH + 1));
				RmLog(LOG_DEBUG, buffer);
				ToDelete.pFrom = (LPTSTR)realloc((void *)ToDelete.pFrom, sizeof(WCHAR)* (CurSize + ReqSize + 1));
				wcscpy((WCHAR *)(&(ToDelete.pFrom[CurSize - 1])), buffer);
				CurSize += ReqSize + 1;
			}

			((LPTSTR)(ToDelete.pFrom))[CurSize - 1] = L'\0';

			free(buffer);

			SHFileOperation(&ToDelete);
			free((void *)(ToDelete.pFrom));
		}

		DragFinish((HDROP)wParam);

		return 0; //An application should return zero if it processes this message.
	}

	return CallWindowProc((WNDPROC)DefaultWndProc, hWnd, uMsg, wParam, lParam);
}

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

PLUGIN_EXPORT void Finalize(void* data)
{
	SkinHWND = RmGetSkinWindow(grm);
	RmLogF(grm, LOG_DEBUG, L"Entered finalize! DefaultWndProc = %x, SkinHWND = %x", DefaultWndProc, SkinHWND);
	DragAcceptFiles(SkinHWND, false);
	RmLogF(grm, LOG_DEBUG, L"Disabled DragAcceptFiles! DefaultWndProc = %x, SkinHWND = %x", DefaultWndProc, SkinHWND);
	SetWindowLongPtr(SkinHWND, GWLP_WNDPROC, (LONG_PTR)DefaultWndProc);
	RmLogF(grm, LOG_DEBUG, L"SetWindowsLongPtr successful? DefaultWndProc = %x, SkinHWND = %x", DefaultWndProc, SkinHWND);
	Measure* measure = (Measure*)data;
	delete measure;
}
Adding this:

Code: Select all

[DragDrop]
Measure=Plugin
Plugin=DragAndDrop
Confirm=FALSE
to your skin .ini file makes it accept dropped files and puts them into recycle bin (with or without confirmation based on Confirm parameter)

Skin I use with this:

Code: Select all

;Images by TomCat94 @ deviantart.com, available at http://tomcat94.deviantart.com/art/Derpy-Recycling-Bin-306520379
[Rainmeter]
Author=gafusss
AppVersion=2003000
Update=100

[RecycleBin]
Measure=Plugin
Plugin=RecycleManager
RecycleType=Count

[DragDrop]
Measure=Plugin
Plugin=DragAndDrop
Confirm=FALSE

[RecycleBinEmpty]
Meter=Image
ImageName=#@#RecycleBin_Empty.png
W=200
H=200
Hidden=0
LeftMouseUpAction=!CommandMeasure RecycleBin OpenBin

[RecycleBinFull]
Meter=Image
ImageName=#@#RecycleBin_Full.png
W=200
H=200
Hidden=1
LeftMouseUpAction=!CommandMeasure RecycleBin OpenBin
RightMouseUpAction=!CommandMeasure RecycleBin EmptyBin

[BinCheck]
Measure=Calc
Formula=RecycleBin
IfAboveValue=0
IfAboveAction=[!HideMeter RecycleBinEmpty][!ShowMeter RecycleBinFull][!Redraw] 

[BinCheck2]
Measure=Calc
Formula=RecycleBin
IfEqualValue=0
IfEqualAction=[!HideMeter RecycleBinFull][!ShowMeter RecycleBinEmpty][!Redraw] 
Hope someone finds it useful :)

I'd like to get some suggestions on how to make it finally work properly.
Can attach the plugin itself later, if needed.

UPD: If crashes occur, please report all available information
Last edited by gafusss on March 17th, 2015, 12:36 pm, edited 1 time in total.
cfixd
Posts: 31
Joined: September 1st, 2014, 1:38 am

Re: [Work in Progress] Drag&Drop trash plugin for recycle bi

Post by cfixd »

It's useful for me and I've tried to improve it though my programming ability is poor.
I've changed some code to avoid crashing, it seems to work in my computer...but still problems

Here's Code in C++ (VS 2013)
#include <Windows.h>
#include "../../API/RainmeterAPI.h"

struct Measure
{
HWND SkinHWND;
Measure() : SkinHWND(NULL) {}
};

static LONG_PTR DefaultWndProc = NULL;
static bool confirm = false;
static void* grm = NULL;

LRESULT CALLBACK DragWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DROPFILES)
{
RmLog(LOG_DEBUG, L"D&D: Got WM_DROPFILES message (DragWndProc)");
UINT FileCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0); //If iFile == 0xFFFFFFFF returns number of files

if (FileCount)
{
SHFILEOPSTRUCT ToDelete;
ToDelete.hwnd = hWnd;
ToDelete.wFunc = FO_DELETE;
ToDelete.pTo = NULL;
ToDelete.fFlags = FOF_ALLOWUNDO;
if (!confirm)
{
ToDelete.fFlags |= FOF_NOCONFIRMATION | FOF_SILENT;
}

ToDelete.pFrom = (LPTSTR)malloc(sizeof(WCHAR) * 1);
UINT CurSize = 1;
LPTSTR buffer = (LPTSTR)malloc(sizeof(WCHAR)* (MAX_PATH + 1));
for (UINT i = 0; i < FileCount; i++)
{
UINT ReqSize = DragQueryFile((HDROP)wParam, i, buffer, (MAX_PATH + 1));
RmLog(LOG_DEBUG, buffer);
ToDelete.pFrom = (LPTSTR)realloc((void *)ToDelete.pFrom, sizeof(WCHAR)* (CurSize + ReqSize + 1));
wcscpy((WCHAR *)(&(ToDelete.pFrom[CurSize - 1])), buffer);
CurSize += ReqSize + 1;
}

((LPTSTR)(ToDelete.pFrom))[CurSize - 1] = L'\0';

free(buffer);

SHFileOperation(&ToDelete);
free((void *)(ToDelete.pFrom));
}

DragFinish((HDROP)wParam);

return 0; //An application should return zero if it processes this message.
}

return ((WNDPROC)DefaultWndProc)(hWnd, uMsg, wParam, lParam);

//return CallWindowProc((WNDPROC)DefaultWndProc, hWnd, uMsg, wParam, lParam); // causing crash ?
}

PLUGIN_EXPORT void Initialize(void** data, void* rm)
{
Measure* measure = new Measure;
*data = measure;

grm = rm;

measure->SkinHWND = RmGetSkinWindow(rm);
RmLogF(rm, LOG_DEBUG, L"HWND == %x (INIT)", measure->SkinHWND);

if (measure->SkinHWND)
{
if (DefaultWndProc = GetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC))
{
RmLogF(rm, LOG_DEBUG, L"DefaultWndProc == %x (INIT)", DefaultWndProc);
SetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC, (LONG_PTR)DragWndProc);
DragAcceptFiles(measure->SkinHWND, true);
}
}
}

PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
Measure* measure = (Measure*)data;

//confirm = RmReadInt(rm, L"Confirm", 0) > 0 ? true : false;
// I think using 0/1 instead of TRUE /FALSE will be better, depending on you.

if (_wcsicmp(RmReadString(rm, L"Confirm", L"FALSE"), L"TRUE") == 0)
{
confirm = true;
}
else
{
confirm = false;
}

RmLogF(rm, LOG_DEBUG, L"confirm == %ls (RELOAD)", confirm ? L"true" : L"false");
RmLogF(rm, LOG_DEBUG, L"D&D: Reload completed");

}

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

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

RmLogF(grm, LOG_DEBUG, L"Entered finalize! DefaultWndProc = %x, SkinHWND = %x", DefaultWndProc, measure->SkinHWND);
DragAcceptFiles(measure->SkinHWND, false);
SetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC, (LONG_PTR)DefaultWndProc);

delete measure;
}
I've builded this version for myself to test,with confirm=0/1 option and without debug log.
Unfortunately I can't download the image from the deviantart because of the GFW.
DragAndDrop_0.0.0.6.rmskin (including plugin and source code)
DragAndDrop_0.0.0.6.rmskin
(73.13 KiB) Downloaded 138 times
Hoping the plugin will be better and waiting for your version, then I can write skin for it.
gafusss
Posts: 2
Joined: September 27th, 2014, 1:48 pm

Re: [Work in Progress] Drag&Drop trash plugin for recycle bi

Post by gafusss »

cfixd wrote:It's useful for me and I've tried to improve it though my programming ability is poor.
I've changed some code to avoid crashing, it seems to work in my computer...but still problems

Here's Code in C++ (VS 2013)
#include <Windows.h>
#include "../../API/RainmeterAPI.h"

struct Measure
{
HWND SkinHWND;
Measure() : SkinHWND(NULL) {}
};

static LONG_PTR DefaultWndProc = NULL;
static bool confirm = false;
static void* grm = NULL;

LRESULT CALLBACK DragWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DROPFILES)
{
RmLog(LOG_DEBUG, L"D&D: Got WM_DROPFILES message (DragWndProc)");
UINT FileCount = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0); //If iFile == 0xFFFFFFFF returns number of files

if (FileCount)
{
SHFILEOPSTRUCT ToDelete;
ToDelete.hwnd = hWnd;
ToDelete.wFunc = FO_DELETE;
ToDelete.pTo = NULL;
ToDelete.fFlags = FOF_ALLOWUNDO;
if (!confirm)
{
ToDelete.fFlags |= FOF_NOCONFIRMATION | FOF_SILENT;
}

ToDelete.pFrom = (LPTSTR)malloc(sizeof(WCHAR) * 1);
UINT CurSize = 1;
LPTSTR buffer = (LPTSTR)malloc(sizeof(WCHAR)* (MAX_PATH + 1));
for (UINT i = 0; i < FileCount; i++)
{
UINT ReqSize = DragQueryFile((HDROP)wParam, i, buffer, (MAX_PATH + 1));
RmLog(LOG_DEBUG, buffer);
ToDelete.pFrom = (LPTSTR)realloc((void *)ToDelete.pFrom, sizeof(WCHAR)* (CurSize + ReqSize + 1));
wcscpy((WCHAR *)(&(ToDelete.pFrom[CurSize - 1])), buffer);
CurSize += ReqSize + 1;
}

((LPTSTR)(ToDelete.pFrom))[CurSize - 1] = L'\0';

free(buffer);

SHFileOperation(&ToDelete);
free((void *)(ToDelete.pFrom));
}

DragFinish((HDROP)wParam);

return 0; //An application should return zero if it processes this message.
}

return ((WNDPROC)DefaultWndProc)(hWnd, uMsg, wParam, lParam);

//return CallWindowProc((WNDPROC)DefaultWndProc, hWnd, uMsg, wParam, lParam); // causing crash ?
}

PLUGIN_EXPORT void Initialize(void** data, void* rm)
{
Measure* measure = new Measure;
*data = measure;

grm = rm;

measure->SkinHWND = RmGetSkinWindow(rm);
RmLogF(rm, LOG_DEBUG, L"HWND == %x (INIT)", measure->SkinHWND);

if (measure->SkinHWND)
{
if (DefaultWndProc = GetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC))
{
RmLogF(rm, LOG_DEBUG, L"DefaultWndProc == %x (INIT)", DefaultWndProc);
SetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC, (LONG_PTR)DragWndProc);
DragAcceptFiles(measure->SkinHWND, true);
}
}
}

PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
Measure* measure = (Measure*)data;

//confirm = RmReadInt(rm, L"Confirm", 0) > 0 ? true : false;
// I think using 0/1 instead of TRUE /FALSE will be better, depending on you.

if (_wcsicmp(RmReadString(rm, L"Confirm", L"FALSE"), L"TRUE") == 0)
{
confirm = true;
}
else
{
confirm = false;
}

RmLogF(rm, LOG_DEBUG, L"confirm == %ls (RELOAD)", confirm ? L"true" : L"false");
RmLogF(rm, LOG_DEBUG, L"D&D: Reload completed");

}

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

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

RmLogF(grm, LOG_DEBUG, L"Entered finalize! DefaultWndProc = %x, SkinHWND = %x", DefaultWndProc, measure->SkinHWND);
DragAcceptFiles(measure->SkinHWND, false);
SetWindowLongPtr(measure->SkinHWND, GWLP_WNDPROC, (LONG_PTR)DefaultWndProc);

delete measure;
}
I've builded this version for myself to test,with confirm=0/1 option and without debug log.
Unfortunately I can't download the image from the deviantart because of the GFW.
DragAndDrop_0.0.0.6.rmskin (including plugin and source code)
DragAndDrop_0.0.0.6.rmskin
Hoping the plugin will be better and waiting for your version, then I can write skin for it.
Thanks for the reply. I've glanced through, like some ideas, will give it a closer look a bit later.
About the crash fix:

Code: Select all

return ((WNDPROC)DefaultWndProc)(hWnd, uMsg, wParam, lParam);

//return CallWindowProc((WNDPROC)DefaultWndProc, hWnd, uMsg, wParam, lParam);	// causing crash ?
According to MSDN:
The subclass window procedure must use the CallWindowProc function to call the original window procedure.
The reason behind it is that DefaultWndProc obtained with GetWindowLongPtr might be not a pointer, but some internal value, meaningful only to CallWindowProc

Did you try my version of plugin and get any crashes? Or only the one you made?
cfixd
Posts: 31
Joined: September 1st, 2014, 1:38 am

Re: [Work in Progress] Drag&Drop trash plugin for recycle bi

Post by cfixd »

My OS version is Win7x64. I get crashes with your version of plugin almost everytime when I close the last skin using this plugin.With the one I made it doesn't crash in my computer,but still crashes in a computer running Win7x86, so the problem remains.
cfixd
Posts: 31
Joined: September 1st, 2014, 1:38 am

Re: [Work in Progress] Drag&Drop trash plugin for recycle bi

Post by cfixd »

I've tried to find the reason,not found yet,it seems to go through well until return.
I found a way to avoid it,to post the message of refresh/deactivate again before meter window get it and set the WNDPROC to default one.
It's based on the source code of rainmeter and works on my computer.
the following code should be added:

Code: Select all

LRESULT CALLBACK DragWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (uMsg == WM_DROPFILES)
	{
		.......
		return 0; //An application should return zero if it processes this message.
	}
	else if ((uMsg == WM_APP + 1) ||					// WM_METERWINDOW_DELAYED_REFRESH 
		(uMsg == WM_COMMAND && wParam == 4024) ||		// IDM_SKIN_REFRESH
		(uMsg == WM_TIMER && wParam == 5))				// TIMER_DEACTIVATE
	{
		// to avoid crash
		DragAcceptFiles(hWnd, false);
		SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)DefaultWndProc);

		PostMessage(hWnd, uMsg, wParam, lParam);
		return 0;
	}

	return CallWindowProc((WNDPROC)DefaultWndProc, hWnd, uMsg, wParam, lParam);
}
User avatar
Virginityrocks
Posts: 478
Joined: February 26th, 2011, 10:22 pm

Re: [Work in Progress] Drag&Drop trash plugin for recycle bi

Post by Virginityrocks »

Watching this thread closely. Is there any way to modify this so that it drags to a specified directory, and not just the recycle bin?
Post Reply