https://git.reactos.org/?p=reactos.git;a=commitdiff;h=46d01bc7fdb55a35fb258a518fc9fef4c11bd303

commit 46d01bc7fdb55a35fb258a518fc9fef4c11bd303
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Sun Feb 23 14:08:36 2025 +0100
Commit:     GitHub <nore...@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);
 }

Reply via email to