mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
RecycleManager.dll:
- Fixed that continuous high CPU usage occurs when recycle bin has a lot of root items - Removed support for the Drives option
This commit is contained in:
parent
a9ee55b194
commit
afa1c7cc20
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,0,0,0
|
FILEVERSION 1,0,1,0
|
||||||
PRODUCTVERSION PRODUCTVER
|
PRODUCTVERSION PRODUCTVER
|
||||||
FILEFLAGSMASK 0x17L
|
FILEFLAGSMASK 0x17L
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -23,7 +23,7 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
BLOCK "040904E4"
|
BLOCK "040904E4"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "FileVersion", "1.0.0.0"
|
VALUE "FileVersion", "1.0.1.0"
|
||||||
VALUE "LegalCopyright", "© 2010 - gschoppe"
|
VALUE "LegalCopyright", "© 2010 - gschoppe"
|
||||||
VALUE "OriginalFilename", "RecycleManager.dll"
|
VALUE "OriginalFilename", "RecycleManager.dll"
|
||||||
VALUE "ProductName", "Rainmeter"
|
VALUE "ProductName", "Rainmeter"
|
||||||
|
@ -16,32 +16,46 @@
|
|||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <stdlib.h>
|
#include <Windows.h>
|
||||||
#include <stdio.h>
|
#include <ShellAPI.h>
|
||||||
#include "../../Library/RawString.h"
|
#include <ShlObj.h>
|
||||||
#include "../../Library/Export.h" // Rainmeter's exported functions
|
#include <process.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "../../Library/Export.h" // Rainmeter's exported functions
|
||||||
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
|
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
|
||||||
|
|
||||||
// System resources that can be counted
|
|
||||||
enum MEASURETYPE
|
|
||||||
{
|
|
||||||
NUMRECYCLE,
|
|
||||||
SIZERECYCLE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MeasureData
|
struct MeasureData
|
||||||
{
|
{
|
||||||
MEASURETYPE type;
|
bool count;
|
||||||
CRawString drives;
|
|
||||||
|
|
||||||
MeasureData() : type(NUMRECYCLE) {}
|
MeasureData() : count(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BinData
|
||||||
|
{
|
||||||
|
FILETIME lastAccess;
|
||||||
|
HANDLE directory;
|
||||||
|
WCHAR drive;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int __stdcall QueryRecycleBinThreadProc(void* pParam);
|
||||||
|
HRESULT GetFolderCLSID(LPCWSTR pszPath, CLSID* pathCLSID);
|
||||||
|
HANDLE GetRecycleBinHandle(WCHAR drive);
|
||||||
|
|
||||||
|
std::vector<BinData> g_BinData;
|
||||||
|
double g_BinCount = 0;
|
||||||
|
double g_BinSize = 0;
|
||||||
|
|
||||||
|
UINT g_InstanceCount = 0;
|
||||||
|
HANDLE g_Thread = NULL;
|
||||||
|
|
||||||
PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
||||||
{
|
{
|
||||||
MeasureData* measure = new MeasureData;
|
MeasureData* measure = new MeasureData;
|
||||||
*data = measure;
|
*data = measure;
|
||||||
|
|
||||||
|
++g_InstanceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||||
@ -51,11 +65,11 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
|||||||
LPCWSTR value = RmReadString(rm, L"RecycleType", L"COUNT");
|
LPCWSTR value = RmReadString(rm, L"RecycleType", L"COUNT");
|
||||||
if (_wcsicmp(L"COUNT", value) == 0)
|
if (_wcsicmp(L"COUNT", value) == 0)
|
||||||
{
|
{
|
||||||
measure->type = NUMRECYCLE;
|
measure->count = true;
|
||||||
}
|
}
|
||||||
else if (_wcsicmp(L"SIZE", value) == 0)
|
else if (_wcsicmp(L"SIZE", value) == 0)
|
||||||
{
|
{
|
||||||
measure->type = SIZERECYCLE;
|
measure->count = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -63,99 +77,239 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
|||||||
_snwprintf_s(buffer, _TRUNCATE, L"RecycleManager.dll: RecycleType=%s is not valid in [%s]", value, RmGetMeasureName(rm));
|
_snwprintf_s(buffer, _TRUNCATE, L"RecycleManager.dll: RecycleType=%s is not valid in [%s]", value, RmGetMeasureName(rm));
|
||||||
RmLog(LOG_ERROR, buffer);
|
RmLog(LOG_ERROR, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = RmReadString(rm, L"Drives", L"ALL");
|
|
||||||
measure->drives = (_wcsicmp(value, L"ALL") == 0) ? NULL : value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT double Update(void* data)
|
PLUGIN_EXPORT double Update(void* data)
|
||||||
{
|
{
|
||||||
MeasureData* measure = (MeasureData*)data;
|
MeasureData* measure = (MeasureData*)data;
|
||||||
double retVal = 0;
|
|
||||||
|
|
||||||
SHQUERYRBINFO rbi = {0};
|
if (!g_Thread)
|
||||||
rbi.cbSize = sizeof(SHQUERYRBINFO);
|
|
||||||
|
|
||||||
if (measure->drives.empty())
|
|
||||||
{
|
{
|
||||||
if (SHQueryRecycleBin(NULL, &rbi) == S_OK)
|
WCHAR buffer[128];
|
||||||
|
DWORD len = GetLogicalDriveStrings(128, buffer);
|
||||||
|
|
||||||
|
// Convert "A:\\\0B:\\\0" -> "AB\0"
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < len; i += 4)
|
||||||
{
|
{
|
||||||
if (measure->type == SIZERECYCLE)
|
buffer[index] = buffer[i];
|
||||||
{
|
++index;
|
||||||
retVal = (double)rbi.i64Size; // size in bytes
|
|
||||||
}
|
|
||||||
else if (measure->type == NUMRECYCLE)
|
|
||||||
{
|
|
||||||
retVal = (double)rbi.i64NumItems; // number of items in bin
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
buffer[index] = L'\0';
|
||||||
else
|
|
||||||
{
|
const WCHAR DRIVE_HANDLED = 1;
|
||||||
WCHAR* drives = _wcsdup(measure->drives.c_str());
|
bool changed = false;
|
||||||
WCHAR* token = wcstok(drives, L"|");
|
auto iter = g_BinData.begin();
|
||||||
while (token)
|
while (iter != g_BinData.end())
|
||||||
{
|
{
|
||||||
if (SHQueryRecycleBin(token, &rbi) == S_OK)
|
BinData& data = (*iter);
|
||||||
|
|
||||||
|
WCHAR* pos = wcschr(buffer, data.drive);
|
||||||
|
if (pos != NULL)
|
||||||
{
|
{
|
||||||
if (measure->type == SIZERECYCLE)
|
*pos = DRIVE_HANDLED;
|
||||||
|
++iter;
|
||||||
|
|
||||||
|
if (data.lastAccess.dwHighDateTime != 0xFFFFFFFF &&
|
||||||
|
data.lastAccess.dwLowDateTime != 0xFFFFFFFF)
|
||||||
{
|
{
|
||||||
retVal += (double)rbi.i64Size; // size in bytes
|
FILETIME lastAccess;
|
||||||
}
|
GetFileTime(data.directory, NULL, &lastAccess, NULL);
|
||||||
else if (measure->type == NUMRECYCLE)
|
if (data.lastAccess.dwHighDateTime != lastAccess.dwHighDateTime ||
|
||||||
{
|
data.lastAccess.dwLowDateTime != lastAccess.dwLowDateTime)
|
||||||
retVal += (double)rbi.i64NumItems; // number of items in bin
|
{
|
||||||
|
data.lastAccess.dwHighDateTime = lastAccess.dwHighDateTime;
|
||||||
|
data.lastAccess.dwLowDateTime = lastAccess.dwLowDateTime;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Drive removed
|
||||||
|
if (data.directory)
|
||||||
|
{
|
||||||
|
CloseHandle(data.directory);
|
||||||
|
}
|
||||||
|
|
||||||
token = wcstok(NULL, L"|");
|
iter = g_BinData.erase(iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(drives);
|
|
||||||
|
for (int i = 0; i < index; ++i)
|
||||||
|
{
|
||||||
|
if (buffer[i] != DRIVE_HANDLED)
|
||||||
|
{
|
||||||
|
// New drive
|
||||||
|
BinData data = {0};
|
||||||
|
data.directory = GetRecycleBinHandle(buffer[i]);
|
||||||
|
data.drive = buffer[i];
|
||||||
|
data.lastAccess.dwHighDateTime =
|
||||||
|
data.lastAccess.dwLowDateTime = data.directory ? 0 : 0xFFFFFFFF;
|
||||||
|
|
||||||
|
g_BinData.push_back(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
g_Thread = (HANDLE)_beginthreadex(NULL, 64 * 1024, QueryRecycleBinThreadProc, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return measure->count ? g_BinCount : g_BinSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Finalize(void* data)
|
PLUGIN_EXPORT void Finalize(void* data)
|
||||||
{
|
{
|
||||||
MeasureData* measure = (MeasureData*)data;
|
MeasureData* measure = (MeasureData*)data;
|
||||||
delete measure;
|
delete measure;
|
||||||
|
|
||||||
|
--g_InstanceCount;
|
||||||
|
if (g_InstanceCount == 0)
|
||||||
|
{
|
||||||
|
for (auto iter = g_BinData.cbegin(); iter != g_BinData.cend(); ++iter)
|
||||||
|
{
|
||||||
|
if ((*iter).directory)
|
||||||
|
{
|
||||||
|
CloseHandle((*iter).directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForSingleObject(g_Thread, INFINITE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
||||||
{
|
{
|
||||||
MeasureData* measure = (MeasureData*)data;
|
MeasureData* measure = (MeasureData*)data;
|
||||||
|
|
||||||
auto emptyBin = [&](DWORD flags)
|
|
||||||
{
|
|
||||||
if (measure->drives.empty())
|
|
||||||
{
|
|
||||||
SHEmptyRecycleBin(NULL, NULL, flags);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WCHAR* drives = _wcsdup(measure->drives.c_str());
|
|
||||||
WCHAR* token = wcstok(drives, L"|");
|
|
||||||
while (token)
|
|
||||||
{
|
|
||||||
SHEmptyRecycleBin(NULL, token, flags);
|
|
||||||
token = wcstok(NULL, L"|");
|
|
||||||
}
|
|
||||||
free(drives);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_wcsicmp(args, L"EmptyBin") == 0)
|
if (_wcsicmp(args, L"EmptyBin") == 0)
|
||||||
{
|
{
|
||||||
emptyBin(0);
|
SHEmptyRecycleBin(NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
else if (_wcsicmp(args, L"EmptyBinSilent") == 0)
|
else if (_wcsicmp(args, L"EmptyBinSilent") == 0)
|
||||||
{
|
{
|
||||||
emptyBin(SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);
|
SHEmptyRecycleBin(NULL, NULL, SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);
|
||||||
}
|
}
|
||||||
else if (_wcsicmp(args, L"OpenBin") == 0)
|
else if (_wcsicmp(args, L"OpenBin") == 0)
|
||||||
{
|
{
|
||||||
// Open the Recycle Bin folder
|
|
||||||
ShellExecute(NULL, L"open", L"explorer.exe", L"/N,::{645FF040-5081-101B-9F08-00AA002F954E}", NULL, SW_SHOW);
|
ShellExecute(NULL, L"open", L"explorer.exe", L"/N,::{645FF040-5081-101B-9F08-00AA002F954E}", NULL, SW_SHOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int __stdcall QueryRecycleBinThreadProc(void* pParam)
|
||||||
|
{
|
||||||
|
SHQUERYRBINFO rbi = {0};
|
||||||
|
rbi.cbSize = sizeof(SHQUERYRBINFO);
|
||||||
|
SHQueryRecycleBin(NULL, &rbi);
|
||||||
|
g_BinCount = (double)rbi.i64NumItems;
|
||||||
|
g_BinSize = (double)rbi.i64Size;
|
||||||
|
|
||||||
|
g_Thread = NULL;
|
||||||
|
|
||||||
|
_endthreadex(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT GetFolderCLSID(LPCWSTR path, CLSID* clsid)
|
||||||
|
{
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
HRESULT hr = SHParseDisplayName(path, NULL, &pidl, 0, NULL);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IShellFolder* sf;
|
||||||
|
LPCITEMIDLIST pidlLast;
|
||||||
|
hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&sf, &pidlLast);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
SHDESCRIPTIONID did;
|
||||||
|
hr = SHGetDataFromIDList(sf, pidlLast, SHGDFIL_DESCRIPTIONID, &did, sizeof(did));
|
||||||
|
*clsid = did.clsid;
|
||||||
|
|
||||||
|
sf->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
CoTaskMemFree(pidl);
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE GetRecycleBinHandle(WCHAR drive)
|
||||||
|
{
|
||||||
|
WCHAR search[] = L"\0:\\*";
|
||||||
|
search[0] = drive;
|
||||||
|
|
||||||
|
WIN32_FIND_DATA fd;
|
||||||
|
HANDLE hSearch = FindFirstFile(search, &fd);
|
||||||
|
if (hSearch != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
std::wstring path;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((fd.dwFileAttributes &
|
||||||
|
(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY)) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR buffer[MAX_PATH];
|
||||||
|
int len = _snwprintf_s(buffer, _TRUNCATE, L"%c:\\%s\\*", drive, fd.cFileName);
|
||||||
|
|
||||||
|
// Find the SID-specific child directory
|
||||||
|
HANDLE hChildSearch = FindFirstFile(buffer, &fd);
|
||||||
|
if (hChildSearch != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (fd.cFileName[0] == L'.'))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.assign(buffer, len - 1);
|
||||||
|
path += fd.cFileName;
|
||||||
|
|
||||||
|
CLSID id;
|
||||||
|
HRESULT hr = GetFolderCLSID(path.c_str(), &id);
|
||||||
|
if (SUCCEEDED(hr) && IsEqualGUID(CLSID_RecycleBin, id))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (FindNextFile(hChildSearch, &fd));
|
||||||
|
|
||||||
|
FindClose(hChildSearch);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
// Break out of main loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (FindNextFile(hSearch, &fd));
|
||||||
|
|
||||||
|
FindClose(hSearch);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
HANDLE hDir = CreateFile(
|
||||||
|
path.c_str(),
|
||||||
|
GENERIC_READ,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return hDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user