Skip to content

Commit 46d01bc

Browse files
authored
[SHIMGVW] Only enable toolbar edit and print buttons if the shell verb exists (reactos#7725)
CORE-20002
1 parent e5fc4de commit 46d01bc

File tree

3 files changed

+126
-35
lines changed

3 files changed

+126
-35
lines changed

dll/win32/shimgvw/shimgvw.c

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ HWND g_hwndFullscreen = NULL;
3333
SHIMGVW_FILENODE * g_pCurrentFile = NULL;
3434
GpImage * g_pImage = NULL;
3535
SHIMGVW_SETTINGS g_Settings;
36+
UINT g_ImageId;
3637

3738
static const UINT s_ZoomSteps[] =
3839
{
@@ -402,6 +403,10 @@ Preview_pLoadImage(PPREVIEW_DATA pData, LPCWSTR szOpenFileName)
402403
Preview_ResetZoom(pData);
403404

404405
Preview_UpdateTitle(pData, szOpenFileName);
406+
407+
++g_ImageId;
408+
EnableCommandIfVerbExists(g_ImageId, g_hMainWnd, IDC_PRINT, L"print", pData->m_szFile);
409+
EnableCommandIfVerbExists(g_ImageId, g_hMainWnd, IDC_MODIFY, L"edit", pData->m_szFile);
405410
}
406411

407412
static VOID
@@ -557,15 +562,17 @@ Preview_pSaveImageAs(PPREVIEW_DATA pData)
557562
static VOID
558563
Preview_pPrintImage(PPREVIEW_DATA pData)
559564
{
560-
/* FIXME */
565+
ShellExecuteVerb(g_hMainWnd, L"print", pData->m_szFile, FALSE);
561566
}
562567

563568
static VOID
564569
Preview_UpdateUI(PPREVIEW_DATA pData)
565570
{
566571
BOOL bEnable = (g_pImage != NULL);
567-
PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable);
568-
PostMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_PRINT, bEnable);
572+
SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_SAVEAS, bEnable);
573+
// These will be validated and enabled later by EnableCommandIfVerbExists
574+
SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_PRINT, FALSE);
575+
SendMessageW(pData->m_hwndToolBar, TB_ENABLEBUTTON, IDC_MODIFY, FALSE);
569576
}
570577

571578
static VOID
@@ -1397,26 +1404,8 @@ Preview_Delete(PPREVIEW_DATA pData)
13971404
static VOID
13981405
Preview_Edit(HWND hwnd)
13991406
{
1400-
SHELLEXECUTEINFOW sei;
1401-
PPREVIEW_DATA pData = Preview_GetData(hwnd);
1402-
1403-
if (!pData->m_szFile[0])
1404-
return;
1405-
1406-
ZeroMemory(&sei, sizeof(sei));
1407-
sei.cbSize = sizeof(sei);
1408-
sei.lpVerb = L"edit";
1409-
sei.lpFile = pData->m_szFile;
1410-
sei.nShow = SW_SHOWNORMAL;
1411-
if (!ShellExecuteExW(&sei))
1412-
{
1413-
DPRINT1("Preview_Edit: ShellExecuteExW() failed with code %ld\n", GetLastError());
1414-
}
1415-
else
1416-
{
1417-
// Destroy the window to quit the application
1418-
DestroyWindow(hwnd);
1419-
}
1407+
PPREVIEW_DATA pData = Preview_GetData(g_hMainWnd);
1408+
ShellExecuteVerb(pData->m_hwnd, L"edit", pData->m_szFile, TRUE);
14201409
}
14211410

14221411
static VOID
@@ -1715,6 +1704,13 @@ PreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
17151704
}
17161705
break;
17171706
}
1707+
case WM_UPDATECOMMANDSTATE:
1708+
{
1709+
PPREVIEW_DATA pData = Preview_GetData(g_hMainWnd);
1710+
if (g_ImageId == lParam)
1711+
SendMessage(pData->m_hwndToolBar, TB_ENABLEBUTTON, LOWORD(wParam), HIWORD(wParam));
1712+
break;
1713+
}
17181714
default:
17191715
{
17201716
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
@@ -1738,6 +1734,7 @@ ImageView_Main(HWND hwnd, LPCWSTR szFileName)
17381734
INITCOMMONCONTROLSEX Icc = { .dwSize = sizeof(Icc), .dwICC = ICC_WIN95_CLASSES };
17391735

17401736
InitCommonControlsEx(&Icc);
1737+
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // Give UI higher priority than background threads
17411738

17421739
/* Initialize COM */
17431740
hrCoInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

dll/win32/shimgvw/shimgvw.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
#include "resource.h"
3232

33+
#define WM_UPDATECOMMANDSTATE (WM_APP + 0)
34+
3335
extern HINSTANCE g_hInstance;
3436
extern GpImage *g_pImage;
3537

@@ -72,6 +74,8 @@ void Anime_Pause(PANIME pAnime);
7274
BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam);
7375

7476
void DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam);
77+
void EnableCommandIfVerbExists(UINT ImageId, HWND hwnd, UINT CmdId, PCWSTR Verb, PCWSTR File);
78+
void ShellExecuteVerb(HWND hwnd, PCWSTR Verb, PCWSTR File, BOOL Quit);
7579
void DisplayHelp(HWND hwnd);
7680

7781
static inline LPVOID QuickAlloc(SIZE_T cbSize, BOOL bZero)

dll/win32/shimgvw/util.c

Lines changed: 102 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@ static void
4747
ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc)
4848
{
4949
HRESULT hr;
50-
UINT id, i;
51-
for (i = 0; i < GetMenuItemCount(hMenu); ++i)
50+
for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
5251
{
5352
WCHAR buf[200];
54-
id = GetMenuItemIdByPos(hMenu, i);
53+
UINT id = GetMenuItemIdByPos(hMenu, i);
5554
if (id == (UINT)-1)
5655
continue;
5756

@@ -131,28 +130,119 @@ DoShellContextMenu(HWND hwnd, IContextMenu *pCM, PCWSTR File, LPARAM lParam)
131130
g_pContextMenu = NULL;
132131
}
133132

134-
void
135-
DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
133+
HRESULT
134+
GetUIObjectOfPath(HWND hwnd, PCWSTR File, REFIID riid, void **ppv)
136135
{
137136
HRESULT hr;
138137
IShellFolder *pSF;
139138
PCUITEMID_CHILD pidlItem;
140139
PIDLIST_ABSOLUTE pidl = ILCreateFromPath(File);
141140
if (pidl && SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pSF), &pidlItem)))
142141
{
143-
IContextMenu *pCM;
144-
hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, &IID_IContextMenu, NULL, (void**)&pCM);
142+
hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, riid, NULL, ppv);
143+
IShellFolder_Release(pSF);
144+
}
145+
SHFree(pidl);
146+
return hr;
147+
}
148+
149+
void
150+
DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
151+
{
152+
IContextMenu *pCM;
153+
HRESULT hr = GetUIObjectOfPath(hwnd, File, IID_PPV_ARG(IContextMenu, &pCM));
154+
if (SUCCEEDED(hr))
155+
{
156+
DoShellContextMenu(hwnd, pCM, File, lParam);
157+
IContextMenu_Release(pCM);
158+
}
159+
}
160+
161+
typedef struct _ENABLECOMMANDDATA
162+
{
163+
HWND hwnd;
164+
PCWSTR Verb;
165+
UINT CmdId;
166+
UINT ImageId;
167+
WCHAR File[ANYSIZE_ARRAY];
168+
} ENABLECOMMANDDATA;
169+
170+
static DWORD CALLBACK
171+
EnableCommandIfVerbExistsProc(LPVOID ThreadParam)
172+
{
173+
enum { first = 1, last = 0x7fff };
174+
ENABLECOMMANDDATA *pData = ThreadParam;
175+
IContextMenu *pCM;
176+
HRESULT hr = GetUIObjectOfPath(pData->hwnd, pData->File, IID_PPV_ARG(IContextMenu, &pCM));
177+
if (SUCCEEDED(hr))
178+
{
179+
HMENU hMenu = CreatePopupMenu();
180+
hr = IContextMenu_QueryContextMenu(pCM, hMenu, 0, first, last, CMF_NORMAL);
145181
if (SUCCEEDED(hr))
146182
{
147-
DoShellContextMenu(hwnd, pCM, File, lParam);
148-
IContextMenu_Release(pCM);
183+
for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
184+
{
185+
WCHAR buf[200];
186+
UINT id = GetMenuItemIdByPos(hMenu, i);
187+
if (id == (UINT)-1)
188+
continue;
189+
190+
*buf = UNICODE_NULL;
191+
hr = IContextMenu_GetCommandString(pCM, id - first, GCS_VERBW, NULL, (char*)buf, _countof(buf));
192+
if (SUCCEEDED(hr) && !lstrcmpiW(buf, pData->Verb))
193+
{
194+
PostMessageW(pData->hwnd, WM_UPDATECOMMANDSTATE, MAKELONG(pData->CmdId, TRUE), pData->ImageId);
195+
break;
196+
}
197+
}
149198
}
150-
IShellFolder_Release(pSF);
199+
DestroyMenu(hMenu);
200+
IContextMenu_Release(pCM);
201+
}
202+
SHFree(pData);
203+
return 0;
204+
}
205+
206+
void
207+
EnableCommandIfVerbExists(UINT ImageId, HWND hwnd, UINT CmdId, PCWSTR Verb, PCWSTR File)
208+
{
209+
const SIZE_T cch = lstrlenW(File) + 1;
210+
ENABLECOMMANDDATA *pData = SHAlloc(FIELD_OFFSET(ENABLECOMMANDDATA, File[cch]));
211+
if (pData)
212+
{
213+
pData->hwnd = hwnd;
214+
pData->Verb = Verb; // Note: This assumes the string is valid for the lifetime of the thread.
215+
pData->CmdId = CmdId;
216+
pData->ImageId = ImageId;
217+
CopyMemory(pData->File, File, cch * sizeof(*File));
218+
SHCreateThread(EnableCommandIfVerbExistsProc, pData, CTF_COINIT | CTF_INSIST, NULL);
151219
}
152-
SHFree(pidl);
153220
}
154221

155-
void DisplayHelp(HWND hwnd)
222+
void
223+
ShellExecuteVerb(HWND hwnd, PCWSTR Verb, PCWSTR File, BOOL Quit)
224+
{
225+
SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_INVOKEIDLIST | SEE_MASK_ASYNCOK };
226+
if (!*File)
227+
return;
228+
229+
sei.hwnd = hwnd;
230+
sei.lpVerb = Verb;
231+
sei.lpFile = File;
232+
sei.nShow = SW_SHOW;
233+
if (!ShellExecuteExW(&sei))
234+
{
235+
DPRINT1("ShellExecuteExW(%ls, %ls) failed with code %ld\n", Verb, File, GetLastError());
236+
}
237+
else if (Quit)
238+
{
239+
// Destroy the window to quit the application
240+
DestroyWindow(hwnd);
241+
}
242+
}
243+
244+
void
245+
DisplayHelp(HWND hwnd)
156246
{
157247
SHELL_ErrorBox(hwnd, ERROR_NOT_SUPPORTED);
158248
}

0 commit comments

Comments
 (0)