https://git.reactos.org/?p=reactos.git;a=commitdiff;h=46d01bc7fdb55a35fb258…
commit 46d01bc7fdb55a35fb258a518fc9fef4c11bd303
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sun Feb 23 14:08:36 2025 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Feb 23 14:08:36 2025 +0100
[SHIMGVW] Only enable toolbar edit and print buttons if the shell verb exists (#7725)
CORE-20002
---
dll/win32/shimgvw/shimgvw.c | 43 ++++++++---------
dll/win32/shimgvw/shimgvw.h | 4 ++
dll/win32/shimgvw/util.c | 114 +++++++++++++++++++++++++++++++++++++++-----
3 files changed, 126 insertions(+), 35 deletions(-)
diff --git a/dll/win32/shimgvw/shimgvw.c b/dll/win32/shimgvw/shimgvw.c
index ba8dd000e81..392a0a463be 100644
--- a/dll/win32/shimgvw/shimgvw.c
+++ b/dll/win32/shimgvw/shimgvw.c
@@ -33,6 +33,7 @@ HWND g_hwndFullscreen = NULL;
SHIMGVW_FILENODE * g_pCurrentFile = NULL;
GpImage * g_pImage = NULL;
SHIMGVW_SETTINGS g_Settings;
+UINT g_ImageId;
static const UINT s_ZoomSteps[] =
{
@@ -402,6 +403,10 @@ Preview_pLoadImage(PPREVIEW_DATA pData, LPCWSTR szOpenFileName)
Preview_ResetZoom(pData);
Preview_UpdateTitle(pData, szOpenFileName);
+
+ ++g_ImageId;
+ EnableCommandIfVerbExists(g_ImageId, g_hMainWnd, IDC_PRINT, L"print",
pData->m_szFile);
+ EnableCommandIfVerbExists(g_ImageId, g_hMainWnd, IDC_MODIFY, L"edit",
pData->m_szFile);
}
static VOID
@@ -557,15 +562,17 @@ Preview_pSaveImageAs(PPREVIEW_DATA pData)
static VOID
Preview_pPrintImage(PPREVIEW_DATA pData)
{
- /* FIXME */
+ ShellExecuteVerb(g_hMainWnd, L"print", pData->m_szFile, FALSE);
}
static VOID
Preview_UpdateUI(PPREVIEW_DATA pData)
{
BOOL bEnable = (g_pImage != NULL);
- PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable);
- PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_PRINT, bEnable);
+ SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable);
+ // These will be validated and enabled later by EnableCommandIfVerbExists
+ SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_PRINT, FALSE);
+ SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_MODIFY, FALSE);
}
static VOID
@@ -1397,26 +1404,8 @@ Preview_Delete(PPREVIEW_DATA pData)
static VOID
Preview_Edit(HWND hwnd)
{
- SHELLEXECUTEINFOW sei;
- PPREVIEW_DATA pData = Preview_GetData(hwnd);
-
- if (!pData->m_szFile[0])
- return;
-
- ZeroMemory(&sei, sizeof(sei));
- sei.cbSize = sizeof(sei);
- sei.lpVerb = L"edit";
- sei.lpFile = pData->m_szFile;
- sei.nShow = SW_SHOWNORMAL;
- if (!ShellExecuteExW(&sei))
- {
- DPRINT1("Preview_Edit: ShellExecuteExW() failed with code %ld\n",
GetLastError());
- }
- else
- {
- // Destroy the window to quit the application
- DestroyWindow(hwnd);
- }
+ PPREVIEW_DATA pData = Preview_GetData(g_hMainWnd);
+ ShellExecuteVerb(pData->m_hwnd, L"edit", pData->m_szFile, TRUE);
}
static VOID
@@ -1715,6 +1704,13 @@ PreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
break;
}
+ case WM_UPDATECOMMANDSTATE:
+ {
+ PPREVIEW_DATA pData = Preview_GetData(g_hMainWnd);
+ if (g_ImageId == lParam)
+ SendMessage(pData->m_hwndToolBar, TB_ENABLEBUTTON, LOWORD(wParam),
HIWORD(wParam));
+ break;
+ }
default:
{
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
@@ -1738,6 +1734,7 @@ ImageView_Main(HWND hwnd, LPCWSTR szFileName)
INITCOMMONCONTROLSEX Icc = { .dwSize = sizeof(Icc), .dwICC = ICC_WIN95_CLASSES };
InitCommonControlsEx(&Icc);
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // Give UI
higher priority than background threads
/* Initialize COM */
hrCoInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
diff --git a/dll/win32/shimgvw/shimgvw.h b/dll/win32/shimgvw/shimgvw.h
index 279d08cd244..cdb6f975fa2 100644
--- a/dll/win32/shimgvw/shimgvw.h
+++ b/dll/win32/shimgvw/shimgvw.h
@@ -30,6 +30,8 @@
#include "resource.h"
+#define WM_UPDATECOMMANDSTATE (WM_APP + 0)
+
extern HINSTANCE g_hInstance;
extern GpImage *g_pImage;
@@ -72,6 +74,8 @@ void Anime_Pause(PANIME pAnime);
BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam);
void DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam);
+void EnableCommandIfVerbExists(UINT ImageId, HWND hwnd, UINT CmdId, PCWSTR Verb, PCWSTR
File);
+void ShellExecuteVerb(HWND hwnd, PCWSTR Verb, PCWSTR File, BOOL Quit);
void DisplayHelp(HWND hwnd);
static inline LPVOID QuickAlloc(SIZE_T cbSize, BOOL bZero)
diff --git a/dll/win32/shimgvw/util.c b/dll/win32/shimgvw/util.c
index 290ad083fad..5a3b8d46294 100644
--- a/dll/win32/shimgvw/util.c
+++ b/dll/win32/shimgvw/util.c
@@ -47,11 +47,10 @@ static void
ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc)
{
HRESULT hr;
- UINT id, i;
- for (i = 0; i < GetMenuItemCount(hMenu); ++i)
+ for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
{
WCHAR buf[200];
- id = GetMenuItemIdByPos(hMenu, i);
+ UINT id = GetMenuItemIdByPos(hMenu, i);
if (id == (UINT)-1)
continue;
@@ -131,8 +130,8 @@ die:
g_pContextMenu = NULL;
}
-void
-DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
+HRESULT
+GetUIObjectOfPath(HWND hwnd, PCWSTR File, REFIID riid, void **ppv)
{
HRESULT hr;
IShellFolder *pSF;
@@ -140,19 +139,110 @@ DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
PIDLIST_ABSOLUTE pidl = ILCreateFromPath(File);
if (pidl && SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder,
&pSF), &pidlItem)))
{
- IContextMenu *pCM;
- hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem,
&IID_IContextMenu, NULL, (void**)&pCM);
+ hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, riid, NULL, ppv);
+ IShellFolder_Release(pSF);
+ }
+ SHFree(pidl);
+ return hr;
+}
+
+void
+DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
+{
+ IContextMenu *pCM;
+ HRESULT hr = GetUIObjectOfPath(hwnd, File, IID_PPV_ARG(IContextMenu, &pCM));
+ if (SUCCEEDED(hr))
+ {
+ DoShellContextMenu(hwnd, pCM, File, lParam);
+ IContextMenu_Release(pCM);
+ }
+}
+
+typedef struct _ENABLECOMMANDDATA
+{
+ HWND hwnd;
+ PCWSTR Verb;
+ UINT CmdId;
+ UINT ImageId;
+ WCHAR File[ANYSIZE_ARRAY];
+} ENABLECOMMANDDATA;
+
+static DWORD CALLBACK
+EnableCommandIfVerbExistsProc(LPVOID ThreadParam)
+{
+ enum { first = 1, last = 0x7fff };
+ ENABLECOMMANDDATA *pData = ThreadParam;
+ IContextMenu *pCM;
+ HRESULT hr = GetUIObjectOfPath(pData->hwnd, pData->File,
IID_PPV_ARG(IContextMenu, &pCM));
+ if (SUCCEEDED(hr))
+ {
+ HMENU hMenu = CreatePopupMenu();
+ hr = IContextMenu_QueryContextMenu(pCM, hMenu, 0, first, last, CMF_NORMAL);
if (SUCCEEDED(hr))
{
- DoShellContextMenu(hwnd, pCM, File, lParam);
- IContextMenu_Release(pCM);
+ for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
+ {
+ WCHAR buf[200];
+ UINT id = GetMenuItemIdByPos(hMenu, i);
+ if (id == (UINT)-1)
+ continue;
+
+ *buf = UNICODE_NULL;
+ hr = IContextMenu_GetCommandString(pCM, id - first, GCS_VERBW, NULL,
(char*)buf, _countof(buf));
+ if (SUCCEEDED(hr) && !lstrcmpiW(buf, pData->Verb))
+ {
+ PostMessageW(pData->hwnd, WM_UPDATECOMMANDSTATE,
MAKELONG(pData->CmdId, TRUE), pData->ImageId);
+ break;
+ }
+ }
}
- IShellFolder_Release(pSF);
+ DestroyMenu(hMenu);
+ IContextMenu_Release(pCM);
+ }
+ SHFree(pData);
+ return 0;
+}
+
+void
+EnableCommandIfVerbExists(UINT ImageId, HWND hwnd, UINT CmdId, PCWSTR Verb, PCWSTR File)
+{
+ const SIZE_T cch = lstrlenW(File) + 1;
+ ENABLECOMMANDDATA *pData = SHAlloc(FIELD_OFFSET(ENABLECOMMANDDATA, File[cch]));
+ if (pData)
+ {
+ pData->hwnd = hwnd;
+ pData->Verb = Verb; // Note: This assumes the string is valid for the lifetime
of the thread.
+ pData->CmdId = CmdId;
+ pData->ImageId = ImageId;
+ CopyMemory(pData->File, File, cch * sizeof(*File));
+ SHCreateThread(EnableCommandIfVerbExistsProc, pData, CTF_COINIT | CTF_INSIST,
NULL);
}
- SHFree(pidl);
}
-void DisplayHelp(HWND hwnd)
+void
+ShellExecuteVerb(HWND hwnd, PCWSTR Verb, PCWSTR File, BOOL Quit)
+{
+ SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_INVOKEIDLIST | SEE_MASK_ASYNCOK };
+ if (!*File)
+ return;
+
+ sei.hwnd = hwnd;
+ sei.lpVerb = Verb;
+ sei.lpFile = File;
+ sei.nShow = SW_SHOW;
+ if (!ShellExecuteExW(&sei))
+ {
+ DPRINT1("ShellExecuteExW(%ls, %ls) failed with code %ld\n", Verb, File,
GetLastError());
+ }
+ else if (Quit)
+ {
+ // Destroy the window to quit the application
+ DestroyWindow(hwnd);
+ }
+}
+
+void
+DisplayHelp(HWND hwnd)
{
SHELL_ErrorBox(hwnd, ERROR_NOT_SUPPORTED);
}