mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
FileView: Added support for opening the properties or context menu for each item. A user-defined item can also be used on parent measures (in case someone wants to open the properties/context menu from another source - a "dummy" parent measure will be needed).
Usage: !CommandMeasure MeasureName ContextMenu !CommandMeasure MeasureName Properties
This commit is contained in:
parent
d0fd184063
commit
05d256ced3
@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PluginFileView.h"
|
#include "PluginFileView.h"
|
||||||
|
#include "../../Common/Platform.h"
|
||||||
|
#include "../../Common/StringUtil.h"
|
||||||
|
|
||||||
#define MAX_LINE_LENGTH 4096
|
#define MAX_LINE_LENGTH 4096
|
||||||
#define INVALID_FILE L"/<>\\"
|
#define INVALID_FILE L"/<>\\"
|
||||||
@ -50,6 +52,7 @@ HRESULT SaveIcon(HICON hIcon, FILE* fp);
|
|||||||
|
|
||||||
static std::vector<ParentMeasure*> g_ParentMeasures;
|
static std::vector<ParentMeasure*> g_ParentMeasures;
|
||||||
static CRITICAL_SECTION g_CriticalSection;
|
static CRITICAL_SECTION g_CriticalSection;
|
||||||
|
static std::string g_SysProperties;
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||||
{
|
{
|
||||||
@ -74,6 +77,15 @@ PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
|||||||
{
|
{
|
||||||
ChildMeasure* child = new ChildMeasure;
|
ChildMeasure* child = new ChildMeasure;
|
||||||
*data = child;
|
*data = child;
|
||||||
|
|
||||||
|
if (g_SysProperties.empty())
|
||||||
|
{
|
||||||
|
std::wstring dir = RmReplaceVariables(rm, L"%WINDIR%");
|
||||||
|
dir.append(L"\\system32\\control.exe");
|
||||||
|
dir.append(Platform::IsAtLeastWinVista() ? L" system" : L" sysdm.cpl");
|
||||||
|
|
||||||
|
g_SysProperties = StringUtil::Narrow(dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||||
@ -98,7 +110,7 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
|||||||
|
|
||||||
if (!child->parent)
|
if (!child->parent)
|
||||||
{
|
{
|
||||||
RmLog(LOG_ERROR, L"FileView.dll: Invalid Path");
|
RmLogF(rm, LOG_ERROR, L"Invalid Path: \"%s\"", path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +122,8 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
|||||||
child->parent->skin = skin;
|
child->parent->skin = skin;
|
||||||
child->parent->name = RmGetMeasureName(rm);
|
child->parent->name = RmGetMeasureName(rm);
|
||||||
child->parent->ownerChild = child;
|
child->parent->ownerChild = child;
|
||||||
|
child->parent->hwnd = RmGetSkinWindow(rm);
|
||||||
|
child->parent->rm = rm;
|
||||||
g_ParentMeasures.push_back(child->parent);
|
g_ParentMeasures.push_back(child->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,20 +509,33 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto runFile = [&](std::wstring& filename, std::wstring& dir)
|
auto runFile = [&](std::wstring fileName, std::wstring dir, bool isProperty) -> void
|
||||||
{
|
{
|
||||||
std::wstring file = dir + filename;
|
// Display computer system properties
|
||||||
|
if (isProperty && dir.empty() && fileName.empty())
|
||||||
|
{
|
||||||
|
WinExec(g_SysProperties.c_str(), SW_SHOWNORMAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||||
|
|
||||||
|
std::wstring file = dir + fileName;
|
||||||
SHELLEXECUTEINFO si = {sizeof(SHELLEXECUTEINFO)};
|
SHELLEXECUTEINFO si = {sizeof(SHELLEXECUTEINFO)};
|
||||||
|
|
||||||
si.lpVerb = nullptr;
|
si.lpVerb = isProperty ? L"properties" : nullptr;
|
||||||
si.lpFile = file.c_str();
|
si.lpFile = file.c_str();
|
||||||
si.nShow = SW_SHOWNORMAL;
|
si.nShow = SW_SHOWNORMAL;
|
||||||
si.lpDirectory = dir.c_str();
|
si.lpDirectory = dir.c_str();
|
||||||
si.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_ASYNCOK;
|
si.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_ASYNCOK;
|
||||||
|
|
||||||
|
if (isProperty) si.fMask |= SEE_MASK_INVOKEIDLIST;
|
||||||
|
|
||||||
ShellExecuteEx(&si);
|
ShellExecuteEx(&si);
|
||||||
|
CoUninitialize();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Parent only commands
|
||||||
if (parent->ownerChild == child)
|
if (parent->ownerChild == child)
|
||||||
{
|
{
|
||||||
if ((int)parent->files.size() > parent->count)
|
if ((int)parent->files.size() > parent->count)
|
||||||
@ -573,57 +600,110 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
|||||||
parent->needsIcons = true;
|
parent->needsIcons = true;
|
||||||
parent->needsUpdating = true;
|
parent->needsUpdating = true;
|
||||||
}
|
}
|
||||||
|
else if (_wcsicmp(args, L"CONTEXTMENU") == 0)
|
||||||
|
{
|
||||||
|
if (!ShowContextMenu(parent->hwnd, parent->path))
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", parent->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(args, L"PROPERTIES") == 0)
|
||||||
|
{
|
||||||
|
runFile(L"", parent->path, true);
|
||||||
|
}
|
||||||
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"PREVIOUSFOLDER") == 0)
|
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"PREVIOUSFOLDER") == 0)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> path = Tokenize(parent->path, L"\\");
|
GetParentFolder(parent->path);
|
||||||
if (path.size() < 2)
|
|
||||||
{
|
|
||||||
parent->path.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent->path.clear();
|
|
||||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
|
||||||
{
|
|
||||||
parent->path += path[i];
|
|
||||||
parent->path += L"\\";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent->indexOffset = 0;
|
parent->indexOffset = 0;
|
||||||
parent->needsUpdating = true;
|
parent->needsUpdating = true;
|
||||||
parent->needsIcons = true;
|
parent->needsIcons = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Special commands that allow for a user defined file/folder
|
||||||
|
std::wstring arg = args;
|
||||||
|
std::wstring::size_type pos = arg.find_first_of(L' ');
|
||||||
|
if (pos != std::wstring::npos)
|
||||||
|
{
|
||||||
|
arg = arg.substr(pos);
|
||||||
|
if (!arg.empty())
|
||||||
|
{
|
||||||
|
arg.erase(0, 1); // Skip the space
|
||||||
|
|
||||||
|
if (_wcsnicmp(args, L"CONTEXTMENU", 11) == 0)
|
||||||
|
{
|
||||||
|
if (!ShowContextMenu(parent->hwnd, arg))
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", arg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsnicmp(args, L"PROPERTIES", 10) == 0)
|
||||||
|
{
|
||||||
|
runFile(arg, L"", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown path: %s", arg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Child only commands
|
||||||
int trueIndex = child->ignoreCount ? child->index : ((child->index % parent->count) + parent->indexOffset);
|
int trueIndex = child->ignoreCount ? child->index : ((child->index % parent->count) + parent->indexOffset);
|
||||||
if (!parent->files.empty() && trueIndex >= 0 && trueIndex < (int)parent->files.size())
|
if (!parent->files.empty() && trueIndex >= 0 && trueIndex < (int)parent->files.size())
|
||||||
{
|
{
|
||||||
if (_wcsicmp(args, L"OPEN") == 0)
|
if (_wcsicmp(args, L"OPEN") == 0)
|
||||||
{
|
{
|
||||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path);
|
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path, false);
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(args, L"CONTEXTMENU") == 0)
|
||||||
|
{
|
||||||
|
std::wstring path = parent->files[trueIndex].path;
|
||||||
|
std::wstring fileName = parent->files[trueIndex].fileName;
|
||||||
|
|
||||||
|
if (_wcsicmp(fileName.c_str(), L"..") == 0)
|
||||||
|
{
|
||||||
|
path = parent->path;
|
||||||
|
GetParentFolder(path);
|
||||||
|
fileName = L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
path.append(fileName);
|
||||||
|
|
||||||
|
if (!ShowContextMenu(parent->hwnd, path))
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(args, L"PROPERTIES") == 0)
|
||||||
|
{
|
||||||
|
std::wstring path = parent->files[trueIndex].path;
|
||||||
|
std::wstring fileName = parent->files[trueIndex].fileName;
|
||||||
|
|
||||||
|
if (_wcsicmp(fileName.c_str(), L"..") == 0)
|
||||||
|
{
|
||||||
|
path = parent->path;
|
||||||
|
GetParentFolder(path);
|
||||||
|
fileName = L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
runFile(fileName, path, true);
|
||||||
}
|
}
|
||||||
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"FOLLOWPATH") == 0)
|
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"FOLLOWPATH") == 0)
|
||||||
{
|
{
|
||||||
if (_wcsicmp(parent->files[trueIndex].fileName.c_str(), L"..") == 0)
|
if (_wcsicmp(parent->files[trueIndex].fileName.c_str(), L"..") == 0)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> path = Tokenize(parent->path, L"\\");
|
GetParentFolder(parent->path);
|
||||||
if (path.size() < 2)
|
|
||||||
{
|
|
||||||
parent->path.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent->path.clear();
|
|
||||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
|
||||||
{
|
|
||||||
parent->path += path[i];
|
|
||||||
parent->path += L"\\";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent->indexOffset = 0;
|
parent->indexOffset = 0;
|
||||||
parent->needsUpdating = true;
|
parent->needsUpdating = true;
|
||||||
@ -643,16 +723,20 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path);
|
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||||
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
RmLog(LOG_ERROR, L"FileView.dll: Invalid command");
|
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Finalize(void* data)
|
PLUGIN_EXPORT void Finalize(void* data)
|
||||||
|
@ -114,6 +114,8 @@ struct ParentMeasure
|
|||||||
int indexOffset;
|
int indexOffset;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
|
|
||||||
|
void* rm;
|
||||||
|
HWND hwnd;
|
||||||
void* skin;
|
void* skin;
|
||||||
LPCWSTR name;
|
LPCWSTR name;
|
||||||
ChildMeasure* ownerChild;
|
ChildMeasure* ownerChild;
|
||||||
@ -139,6 +141,8 @@ struct ParentMeasure
|
|||||||
skin(nullptr),
|
skin(nullptr),
|
||||||
name(),
|
name(),
|
||||||
ownerChild(nullptr),
|
ownerChild(nullptr),
|
||||||
|
rm(),
|
||||||
|
hwnd(),
|
||||||
thread(nullptr),
|
thread(nullptr),
|
||||||
fileCount(0),
|
fileCount(0),
|
||||||
folderCount(0),
|
folderCount(0),
|
||||||
@ -188,6 +192,81 @@ std::vector<std::wstring> Tokenize(const std::wstring& str, const std::wstring&
|
|||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetParentFolder(std::wstring& path)
|
||||||
|
{
|
||||||
|
std::vector<std::wstring> tokens = Tokenize(path, L"\\");
|
||||||
|
if (tokens.size() < 2)
|
||||||
|
{
|
||||||
|
path.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path.clear();
|
||||||
|
for (size_t i = 0; i < tokens.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
path += tokens[i];
|
||||||
|
path += L"\\";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShowContextMenu(HWND hwnd, std::wstring& path)
|
||||||
|
{
|
||||||
|
POINT pos;
|
||||||
|
GetCursorPos(&pos);
|
||||||
|
|
||||||
|
// If the mouse is outside of the boundaries of
|
||||||
|
// the skin, use the upper-left corner of the skin
|
||||||
|
RECT rect;
|
||||||
|
GetWindowRect(hwnd, &rect);
|
||||||
|
if (pos.x < rect.left || pos.x > rect.right ||
|
||||||
|
pos.y < rect.top || pos.y > rect.bottom)
|
||||||
|
{
|
||||||
|
pos.x = rect.left;
|
||||||
|
pos.y = rect.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITEMIDLIST* id = nullptr;
|
||||||
|
HRESULT result = SHParseDisplayName(path.c_str(), nullptr, &id, 0, nullptr);
|
||||||
|
if (!SUCCEEDED(result) || !id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IShellFolder* iFolder = nullptr;
|
||||||
|
LPCITEMIDLIST idChild = nullptr;
|
||||||
|
result = SHBindToParent(id, IID_IShellFolder, (void**)&iFolder, &idChild);
|
||||||
|
if (!SUCCEEDED(result) || !iFolder)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IContextMenu* iMenu = nullptr;
|
||||||
|
result = iFolder->GetUIObjectOf(hwnd, 1, (const ITEMIDLIST **)&idChild, IID_IContextMenu, nullptr, (void**)&iMenu);
|
||||||
|
if (!SUCCEEDED(result) || !iFolder)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HMENU hMenu = CreatePopupMenu();
|
||||||
|
if (!hMenu)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (SUCCEEDED(iMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_NORMAL)))
|
||||||
|
{
|
||||||
|
int iCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pos.x, pos.y, hwnd, NULL);
|
||||||
|
if (iCmd > 0)
|
||||||
|
{
|
||||||
|
CMINVOKECOMMANDINFOEX info = { 0 };
|
||||||
|
info.cbSize = sizeof(info);
|
||||||
|
info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_ASYNCOK;
|
||||||
|
info.hwnd = hwnd;
|
||||||
|
info.lpVerb = MAKEINTRESOURCEA(iCmd - 1);
|
||||||
|
info.lpVerbW = MAKEINTRESOURCEW(iCmd - 1);
|
||||||
|
info.nShow = SW_SHOWNORMAL;
|
||||||
|
|
||||||
|
iMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyMenu(hMenu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*std::wstring UINT64_To_String(UINT64 value)
|
/*std::wstring UINT64_To_String(UINT64 value)
|
||||||
{
|
{
|
||||||
std::wstring result;
|
std::wstring result;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 2,0,2,0
|
FILEVERSION 2,0,3,0
|
||||||
PRODUCTVERSION PRODUCTVER
|
PRODUCTVERSION PRODUCTVER
|
||||||
FILEFLAGSMASK 0x17L
|
FILEFLAGSMASK 0x17L
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -23,7 +23,7 @@ VS_VERSION_INFO VERSIONINFO
|
|||||||
{
|
{
|
||||||
BLOCK "040904E4"
|
BLOCK "040904E4"
|
||||||
{
|
{
|
||||||
VALUE "FileVersion", "2.0.2.0"
|
VALUE "FileVersion", "2.0.3.0"
|
||||||
VALUE "LegalCopyright", "© 2012 - Brian Ferguson"
|
VALUE "LegalCopyright", "© 2012 - Brian Ferguson"
|
||||||
VALUE "ProductName", "Rainmeter"
|
VALUE "ProductName", "Rainmeter"
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
@ -36,6 +36,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="PluginFileView.rc" />
|
<ResourceCompile Include="PluginFileView.rc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Common.vcxproj">
|
||||||
|
<Project>{19312085-aa51-4bd6-be92-4b6098cca539}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <Shellapi.h>
|
#include <Shellapi.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
|
#include <ShlObj.h>
|
||||||
|
|
||||||
// STL
|
// STL
|
||||||
#include <string>
|
#include <string>
|
||||||
|
Loading…
Reference in New Issue
Block a user