[SHIMGVW] Only enable toolbar edit and print buttons if the shell verb exists (#7725)

CORE-20002
This commit is contained in:
Whindmar Saksit 2025-02-23 14:08:36 +01:00 committed by GitHub
parent e5fc4de8c9
commit 46d01bc7fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 127 additions and 36 deletions

View file

@ -33,6 +33,7 @@ HWND g_hwndFullscreen = NULL;
SHIMGVW_FILENODE * g_pCurrentFile = NULL; SHIMGVW_FILENODE * g_pCurrentFile = NULL;
GpImage * g_pImage = NULL; GpImage * g_pImage = NULL;
SHIMGVW_SETTINGS g_Settings; SHIMGVW_SETTINGS g_Settings;
UINT g_ImageId;
static const UINT s_ZoomSteps[] = static const UINT s_ZoomSteps[] =
{ {
@ -402,6 +403,10 @@ Preview_pLoadImage(PPREVIEW_DATA pData, LPCWSTR szOpenFileName)
Preview_ResetZoom(pData); Preview_ResetZoom(pData);
Preview_UpdateTitle(pData, szOpenFileName); 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 static VOID
@ -557,15 +562,17 @@ Preview_pSaveImageAs(PPREVIEW_DATA pData)
static VOID static VOID
Preview_pPrintImage(PPREVIEW_DATA pData) Preview_pPrintImage(PPREVIEW_DATA pData)
{ {
/* FIXME */ ShellExecuteVerb(g_hMainWnd, L"print", pData->m_szFile, FALSE);
} }
static VOID static VOID
Preview_UpdateUI(PPREVIEW_DATA pData) Preview_UpdateUI(PPREVIEW_DATA pData)
{ {
BOOL bEnable = (g_pImage != NULL); BOOL bEnable = (g_pImage != NULL);
PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable); SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable);
PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_PRINT, 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 static VOID
@ -1397,26 +1404,8 @@ Preview_Delete(PPREVIEW_DATA pData)
static VOID static VOID
Preview_Edit(HWND hwnd) Preview_Edit(HWND hwnd)
{ {
SHELLEXECUTEINFOW sei; PPREVIEW_DATA pData = Preview_GetData(g_hMainWnd);
PPREVIEW_DATA pData = Preview_GetData(hwnd); ShellExecuteVerb(pData->m_hwnd, L"edit", pData->m_szFile, TRUE);
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);
}
} }
static VOID static VOID
@ -1715,6 +1704,13 @@ PreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} }
break; 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: default:
{ {
return DefWindowProcW(hwnd, uMsg, wParam, lParam); 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 = { .dwSize = sizeof(Icc), .dwICC = ICC_WIN95_CLASSES };
InitCommonControlsEx(&Icc); InitCommonControlsEx(&Icc);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // Give UI higher priority than background threads
/* Initialize COM */ /* Initialize COM */
hrCoInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); hrCoInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

View file

@ -30,6 +30,8 @@
#include "resource.h" #include "resource.h"
#define WM_UPDATECOMMANDSTATE (WM_APP + 0)
extern HINSTANCE g_hInstance; extern HINSTANCE g_hInstance;
extern GpImage *g_pImage; extern GpImage *g_pImage;
@ -72,6 +74,8 @@ void Anime_Pause(PANIME pAnime);
BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam); BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam);
void DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam); 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); void DisplayHelp(HWND hwnd);
static inline LPVOID QuickAlloc(SIZE_T cbSize, BOOL bZero) static inline LPVOID QuickAlloc(SIZE_T cbSize, BOOL bZero)

View file

@ -47,11 +47,10 @@ static void
ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc) ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc)
{ {
HRESULT hr; HRESULT hr;
UINT id, i; for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
for (i = 0; i < GetMenuItemCount(hMenu); ++i)
{ {
WCHAR buf[200]; WCHAR buf[200];
id = GetMenuItemIdByPos(hMenu, i); UINT id = GetMenuItemIdByPos(hMenu, i);
if (id == (UINT)-1) if (id == (UINT)-1)
continue; continue;
@ -131,8 +130,8 @@ die:
g_pContextMenu = NULL; g_pContextMenu = NULL;
} }
void HRESULT
DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam) GetUIObjectOfPath(HWND hwnd, PCWSTR File, REFIID riid, void **ppv)
{ {
HRESULT hr; HRESULT hr;
IShellFolder *pSF; IShellFolder *pSF;
@ -140,19 +139,110 @@ DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
PIDLIST_ABSOLUTE pidl = ILCreateFromPath(File); PIDLIST_ABSOLUTE pidl = ILCreateFromPath(File);
if (pidl && SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pSF), &pidlItem))) if (pidl && SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pSF), &pidlItem)))
{ {
IContextMenu *pCM; hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, riid, NULL, ppv);
hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, &IID_IContextMenu, NULL, (void**)&pCM);
if (SUCCEEDED(hr))
{
DoShellContextMenu(hwnd, pCM, File, lParam);
IContextMenu_Release(pCM);
}
IShellFolder_Release(pSF); IShellFolder_Release(pSF);
} }
SHFree(pidl); SHFree(pidl);
return hr;
} }
void DisplayHelp(HWND hwnd) 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))
{
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;
}
}
}
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);
}
}
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); SHELL_ErrorBox(hwnd, ERROR_NOT_SUPPORTED);
} }