[SHELL32][SHELL32_APITEST] Handle named registry verbs in CDefaultContextMenu::InvokeCommand (#9340)

CORE-20690
This commit is contained in:
Whindmar Saksit
2026-08-04 18:39:14 +02:00
committed by GitHub
parent ded9969049
commit 16bb138e32
10 changed files with 180 additions and 137 deletions
+59 -29
View File
@@ -17,6 +17,19 @@ CCopyMoveToMenu::CCopyMoveToMenu() :
{ {
} }
static BOOL
IsValidTarget(CCopyMoveToMenu *pThis, LPCITEMIDLIST pidl)
{
WCHAR szPath[MAX_PATH];
if (ILIsEqual(pidl, pThis->m_pidlFolder))
return pThis->GetFileOp() == FO_COPY;
szPath[0] = UNICODE_NULL;
SHGetPathFromIDListW(pidl, szPath);
return _ILIsDesktop(pidl) || PathFileExistsW(szPath);
}
static LRESULT CALLBACK static LRESULT CALLBACK
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
@@ -62,20 +75,12 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static INT CALLBACK static INT CALLBACK
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{ {
CCopyMoveToMenu *this_ = CCopyMoveToMenu *this_ = reinterpret_cast<CCopyMoveToMenu*>(lpData);
reinterpret_cast<CCopyMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
switch (uMsg) switch (uMsg)
{ {
case BFFM_INITIALIZED: case BFFM_INITIALIZED:
{ {
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
this_ = reinterpret_cast<CCopyMoveToMenu *>(lpData);
// Select initial directory
SendMessageW(hwnd, BFFM_SETSELECTION, FALSE,
reinterpret_cast<LPARAM>(static_cast<LPCITEMIDLIST>(this_->m_pidlFolder)));
// Set caption // Set caption
CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID())); CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID()));
SetWindowTextW(hwnd, strCaption); SetWindowTextW(hwnd, strCaption);
@@ -85,31 +90,30 @@ BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
SetDlgItemText(hwnd, IDOK, strCopyOrMove); SetDlgItemText(hwnd, IDOK, strCopyOrMove);
// Subclassing // Subclassing
// TODO: Replace this with BIF_VALIDATE
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
this_->m_fnOldWndProc = this_->m_fnOldWndProc =
reinterpret_cast<WNDPROC>( reinterpret_cast<WNDPROC>(
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc))); SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
// Disable OK // Expand "My Computer"
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE); CComHeapPtr<ITEMIDLIST> drivesPidl(SHCloneSpecialIDList(hwnd, CSIDL_DRIVES, TRUE));
if (drivesPidl)
SendMessageW(hwnd, BFFM_SETEXPANDED, FALSE, (LPARAM)(LPITEMIDLIST)drivesPidl);
// Select initial directory
// TODO: Remember the last directory used by the user
CComHeapPtr<ITEMIDLIST> pidl(SHCloneSpecialIDList(hwnd, CSIDL_PERSONAL, TRUE));
if (pidl)
SendMessageW(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)(LPITEMIDLIST)pidl);
SendMessageW(hwnd, BFFM_ENABLEOK, 0, pidl && IsValidTarget(this_, pidl));
break; break;
} }
case BFFM_SELCHANGED: case BFFM_SELCHANGED:
{ {
if (!this_)
break;
WCHAR szPath[MAX_PATH];
LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam); LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
PostMessageW(hwnd, BFFM_ENABLEOK, 0, IsValidTarget(this_, pidl));
szPath[0] = 0;
SHGetPathFromIDListW(pidl, szPath);
if (ILIsEqual(pidl, this_->m_pidlFolder))
PostMessageW(hwnd, BFFM_ENABLEOK, 0, this_->GetFileOp() == FO_COPY);
else if (PathFileExistsW(szPath) || _ILIsDesktop(pidl))
PostMessageW(hwnd, BFFM_ENABLEOK, 0, TRUE);
else
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE);
// the text box will be updated later soon, ignore it // the text box will be updated later soon, ignore it
this_->m_bIgnoreTextBoxChange = TRUE; this_->m_bIgnoreTextBoxChange = TRUE;
@@ -123,6 +127,7 @@ BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
HRESULT HRESULT
CCopyMoveToMenu::DoRealFileOp(const CIDA *pCIDA, LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidlDestination) CCopyMoveToMenu::DoRealFileOp(const CIDA *pCIDA, LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidlDestination)
{ {
// TODO: Use SH32_SimulateDropWithSite instead
CStringW strFiles; CStringW strFiles;
WCHAR szPath[MAX_PATH]; WCHAR szPath[MAX_PATH];
for (UINT n = 0; n < pCIDA->cidl; ++n) for (UINT n = 0; n < pCIDA->cidl; ++n)
@@ -340,15 +345,13 @@ CCopyMoveToMenu::GetCommandString(
LPSTR pszName, LPSTR pszName,
UINT cchMax) UINT cchMax)
{ {
#if 1 // Windows does not implement any of these but we will continue to do so as long as we (incorrectly) show them in the context menu
if ((uType | GCS_UNICODE) == GCS_VALIDATEW) if ((uType | GCS_UNICODE) == GCS_VALIDATEW)
return idCmd == IDC_ACTION ? S_OK : S_FALSE; return idCmd == IDC_ACTION ? S_OK : S_FALSE;
if (uType == GCS_VERBW && idCmd == IDC_ACTION) if (uType == GCS_VERBW && idCmd == IDC_ACTION)
return SHAnsiToUnicode(GetVerb(), (LPWSTR)pszName, cchMax); return SHAnsiToUnicode(GetVerb(), (LPWSTR)pszName, cchMax);
#endif
FIXME("%p %lu %u %p %p %u\n", this,
idCmd, uType, pwReserved, pszName, cchMax);
return E_NOTIMPL; return E_NOTIMPL;
} }
@@ -398,3 +401,30 @@ CCopyMoveToMenu::GetSite(REFIID riid, void **ppvSite)
return m_pSite->QueryInterface(riid, ppvSite); return m_pSite->QueryInterface(riid, ppvSite);
} }
HRESULT
CCopyMoveToMenu::DoCopyMoveToFolder(BOOL Copy, HWND hWnd, IUnknown *pSite,
IShellFolder *pSF, UINT cidl, PCUITEMID_CHILD_ARRAY pidls)
{
SFGAOF attr = SFGAO_CANCOPY | SFGAO_CANMOVE;
HRESULT hr = pSF->GetAttributesOf(cidl, pidls, &attr);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (!(attr & (Copy ? SFGAO_CANCOPY : SFGAO_CANMOVE)))
return E_INVALIDARG;
CComPtr<IDataObject> pDO;
hr = pSF->GetUIObjectOf(hWnd, cidl, pidls, IID_NULL_PPV_ARG(IDataObject, &pDO));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
REFCLSID clsid = Copy ? CLSID_CopyToMenu : CLSID_MoveToMenu;
CComPtr<IContextMenu> pCM;
hr = SHELL_InitializeExtension(clsid, NULL, pDO, NULL, IID_PPV_ARG(IContextMenu, &pCM));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
IUnknown_SetSite(pCM, pSite);
CMINVOKECOMMANDINFO ici = { sizeof(ici), 0, hWnd, MAKEINTRESOURCEA(IDC_ACTION), NULL, NULL, SW_SHOW };
return pCM->InvokeCommand(&ici);
}
+2
View File
@@ -46,6 +46,8 @@ public:
// IObjectWithSite // IObjectWithSite
STDMETHODIMP SetSite(IUnknown *pUnkSite) override; STDMETHODIMP SetSite(IUnknown *pUnkSite) override;
STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override; STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override;
static HRESULT DoCopyMoveToFolder(BOOL Copy, HWND hWnd, IUnknown *pSite, IShellFolder *pSF, UINT cidl, PCUITEMID_CHILD_ARRAY pidls);
}; };
class CCopyToMenu class CCopyToMenu
+3 -19
View File
@@ -2487,25 +2487,9 @@ void CDefView::DoActivate(UINT uState)
void CDefView::_DoCopyToMoveToFolder(BOOL bCopy) void CDefView::_DoCopyToMoveToFolder(BOOL bCopy)
{ {
if (!GetSelections()) if (GetSelections())
return; CCopyMoveToMenu::DoCopyMoveToFolder(bCopy, m_hWnd, static_cast<IDropTarget*>(this),
m_pSFParent, m_cidl, m_apidl);
SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM;
HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
if (FAILED_UNEXPECTEDLY(hr))
return;
if (!bCopy && !(rfg & SFGAO_CANMOVE))
return;
if (bCopy && !(rfg & SFGAO_CANCOPY))
return;
CComPtr<IContextMenu> pCM;
hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM);
if (FAILED_UNEXPECTEDLY(hr))
return;
InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL);
} }
LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+27 -70
View File
@@ -164,10 +164,7 @@ static const struct _StaticInvokeCommandMap_
SHORT DfmCmd; SHORT DfmCmd;
} g_StaticInvokeCmdMap[] = } g_StaticInvokeCmdMap[] =
{ {
{ "runas", 0 }, // Unimplemented // Note: Verbs from the registry should not be listed here
{ "print", 0 }, // Unimplemented
{ "preview", 0 }, // Unimplemented
{ "open", FCIDM_SHVIEW_OPEN },
{ CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER, (SHORT)DFM_CMD_NEWFOLDER }, { CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER, (SHORT)DFM_CMD_NEWFOLDER },
{ "cut", FCIDM_SHVIEW_CUT, /* ? */ }, { "cut", FCIDM_SHVIEW_CUT, /* ? */ },
{ "copy", FCIDM_SHVIEW_COPY, (SHORT)DFM_CMD_COPY }, { "copy", FCIDM_SHVIEW_COPY, (SHORT)DFM_CMD_COPY },
@@ -176,8 +173,6 @@ static const struct _StaticInvokeCommandMap_
{ "delete", FCIDM_SHVIEW_DELETE, (SHORT)DFM_CMD_DELETE }, { "delete", FCIDM_SHVIEW_DELETE, (SHORT)DFM_CMD_DELETE },
{ "properties", FCIDM_SHVIEW_PROPERTIES, (SHORT)DFM_CMD_PROPERTIES }, { "properties", FCIDM_SHVIEW_PROPERTIES, (SHORT)DFM_CMD_PROPERTIES },
{ "rename", FCIDM_SHVIEW_RENAME, (SHORT)DFM_CMD_RENAME }, { "rename", FCIDM_SHVIEW_RENAME, (SHORT)DFM_CMD_RENAME },
{ "copyto", FCIDM_SHVIEW_COPYTO },
{ "moveto", FCIDM_SHVIEW_MOVETO },
}; };
PCSTR MapFcidmCmdToVerb(_In_ UINT_PTR CmdId) PCSTR MapFcidmCmdToVerb(_In_ UINT_PTR CmdId)
@@ -328,7 +323,6 @@ class CDefaultContextMenu :
UINT AddShellExtensionsToMenu(HMENU hMenu, UINT* pIndexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); UINT AddShellExtensionsToMenu(HMENU hMenu, UINT* pIndexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT* IndexMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags); UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT* IndexMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
HRESULT DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink); HRESULT DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink);
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoDelete(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT DoDelete(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bCopy); HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bCopy);
@@ -336,7 +330,6 @@ class CDefaultContextMenu :
HRESULT DoProperties(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT DoProperties(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoUndo(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT DoUndo(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoCreateNewFolder(LPCMINVOKECOMMANDINFOEX lpici); HRESULT DoCreateNewFolder(LPCMINVOKECOMMANDINFOEX lpici);
HRESULT DoCopyToMoveToFolder(LPCMINVOKECOMMANDINFOEX lpici, BOOL bCopy);
HRESULT InvokeShellExt(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT InvokeShellExt(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT InvokeRegVerb(LPCMINVOKECOMMANDINFOEX lpcmi); HRESULT InvokeRegVerb(LPCMINVOKECOMMANDINFOEX lpcmi);
DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStaticShellEntry pEntry); DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStaticShellEntry pEntry);
@@ -345,6 +338,11 @@ class CDefaultContextMenu :
PDynamicShellEntry GetDynamicEntry(UINT idCmd); PDynamicShellEntry GetDynamicEntry(UINT idCmd);
BOOL MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode); BOOL MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode);
HRESULT GetNoAssocError()
{
return LOBYTE(GetVersion()) < 6 ? E_INVALIDARG : HResultFromWin32(ERROR_NO_ASSOCIATION);
}
public: public:
CDefaultContextMenu(); CDefaultContextMenu();
~CDefaultContextMenu(); ~CDefaultContextMenu();
@@ -1108,13 +1106,6 @@ HRESULT CDefaultContextMenu::DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink)
return S_OK; return S_OK;
} }
HRESULT
CDefaultContextMenu::DoOpenOrExplore(LPCMINVOKECOMMANDINFOEX lpcmi)
{
UNIMPLEMENTED;
return E_FAIL;
}
HRESULT CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi) HRESULT CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi)
{ {
HRESULT hr = _DoInvokeCommandCallback(lpcmi, DFM_CMD_LINK); HRESULT hr = _DoInvokeCommandCallback(lpcmi, DFM_CMD_LINK);
@@ -1239,43 +1230,6 @@ CDefaultContextMenu::DoUndo(LPCMINVOKECOMMANDINFOEX lpcmi)
return E_NOTIMPL; return E_NOTIMPL;
} }
HRESULT
CDefaultContextMenu::DoCopyToMoveToFolder(LPCMINVOKECOMMANDINFOEX lpici, BOOL bCopy)
{
HRESULT hr = E_FAIL;
if (!m_pDataObj)
{
ERR("m_pDataObj is NULL\n");
return hr;
}
CComPtr<IContextMenu> pContextMenu;
if (bCopy)
hr = SHCoCreateInstance(NULL, &CLSID_CopyToMenu, NULL,
IID_PPV_ARG(IContextMenu, &pContextMenu));
else
hr = SHCoCreateInstance(NULL, &CLSID_MoveToMenu, NULL,
IID_PPV_ARG(IContextMenu, &pContextMenu));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComPtr<IShellExtInit> pInit;
hr = pContextMenu->QueryInterface(IID_PPV_ARG(IShellExtInit, &pInit));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pInit->Initialize(m_pidlFolder, m_pDataObj, NULL);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (bCopy)
lpici->lpVerb = "copyto";
else
lpici->lpVerb = "moveto";
return pContextMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)lpici);
}
// This code is taken from CNewMenu and should be shared between the 2 classes // This code is taken from CNewMenu and should be shared between the 2 classes
HRESULT HRESULT
CDefaultContextMenu::DoCreateNewFolder( CDefaultContextMenu::DoCreateNewFolder(
@@ -1358,18 +1312,16 @@ BOOL
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode) CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
{ {
WCHAR UnicodeStr[MAX_VERB]; WCHAR UnicodeStr[MAX_VERB];
UINT i;
/* Loop through all the static verbs looking for a match */ /* Loop through all the static verbs looking for a match */
for (UINT i = 0; i < _countof(g_StaticInvokeCmdMap); i++) for (i = 0; i < _countof(g_StaticInvokeCmdMap); i++)
{ {
/* We can match both ANSI and unicode strings */
if (IsUnicode) if (IsUnicode)
{ {
/* The static verbs are ANSI, get a unicode version before doing the compare */
SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, UnicodeStr, MAX_VERB); SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, UnicodeStr, MAX_VERB);
if (!_wcsicmp(UnicodeStr, (LPWSTR)Verb)) if (!_wcsicmp(UnicodeStr, (LPWSTR)Verb))
{ {
/* Return the Corresponding Id */
*idCmd = g_StaticInvokeCmdMap[i].IntVerb; *idCmd = g_StaticInvokeCmdMap[i].IntVerb;
return TRUE; return TRUE;
} }
@@ -1384,7 +1336,22 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
} }
} }
for (POSITION it = m_DynamicEntries.GetHeadPosition(); it != NULL;) POSITION it;
HRESULT hr = S_OK;
// Check the registry verbs
if (!IsUnicode)
hr = StringCchPrintfW(UnicodeStr, _countof(UnicodeStr), L"%hs", Verb);
for (i = 0, it = m_StaticEntries.GetHeadPosition(); it && SUCCEEDED(hr); ++i)
{
StaticShellEntry& entry = m_StaticEntries.GetNext(it);
if (!_wcsicmp(entry.Verb, UnicodeStr))
{
*idCmd = m_iIdSCMFirst + i;
return TRUE;
}
}
for (it = m_DynamicEntries.GetHeadPosition(); it != NULL;)
{ {
DynamicShellEntry& entry = m_DynamicEntries.GetNext(it); DynamicShellEntry& entry = m_DynamicEntries.GetNext(it);
if (!entry.NumIds) if (!entry.NumIds)
@@ -1396,7 +1363,7 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
return TRUE; return TRUE;
} }
} }
return FALSE; return FALSE; // Note: Even if the verb is "open", we must fail if we can't find a handler
} }
HRESULT HRESULT
@@ -1547,7 +1514,7 @@ CDefaultContextMenu::InvokeRegVerb(
POSITION it = m_StaticEntries.FindIndex(iCmd); POSITION it = m_StaticEntries.FindIndex(iCmd);
if (it == NULL) if (it == NULL)
return E_INVALIDARG; return HResultFromWin32(ERROR_NO_ASSOCIATION);
PStaticShellEntry pEntry = &m_StaticEntries.GetAt(it); PStaticShellEntry pEntry = &m_StaticEntries.GetAt(it);
@@ -1670,7 +1637,7 @@ CDefaultContextMenu::InvokeCommand(
if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE)) if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE))
LocalInvokeInfo.lpVerb = MAKEINTRESOURCEA(CmdId); LocalInvokeInfo.lpVerb = MAKEINTRESOURCEA(CmdId);
else else
return E_INVALIDARG; return GetNoAssocError();
} }
CmdId = LOWORD(LocalInvokeInfo.lpVerb); CmdId = LOWORD(LocalInvokeInfo.lpVerb);
@@ -1719,10 +1686,6 @@ CDefaultContextMenu::InvokeCommand(
case FCIDM_SHVIEW_INSERTLINK: case FCIDM_SHVIEW_INSERTLINK:
Result = DoPaste(&LocalInvokeInfo, TRUE); Result = DoPaste(&LocalInvokeInfo, TRUE);
break; break;
case FCIDM_SHVIEW_OPEN:
case FCIDM_SHVIEW_EXPLORE:
Result = DoOpenOrExplore(&LocalInvokeInfo);
break;
case FCIDM_SHVIEW_COPY: case FCIDM_SHVIEW_COPY:
case FCIDM_SHVIEW_CUT: case FCIDM_SHVIEW_CUT:
Result = DoCopyOrCut(&LocalInvokeInfo, CmdId == FCIDM_SHVIEW_COPY); Result = DoCopyOrCut(&LocalInvokeInfo, CmdId == FCIDM_SHVIEW_COPY);
@@ -1742,12 +1705,6 @@ CDefaultContextMenu::InvokeCommand(
case FCIDM_SHVIEW_NEWFOLDER: case FCIDM_SHVIEW_NEWFOLDER:
Result = DoCreateNewFolder(&LocalInvokeInfo); Result = DoCreateNewFolder(&LocalInvokeInfo);
break; break;
case FCIDM_SHVIEW_COPYTO:
Result = DoCopyToMoveToFolder(&LocalInvokeInfo, TRUE);
break;
case FCIDM_SHVIEW_MOVETO:
Result = DoCopyToMoveToFolder(&LocalInvokeInfo, FALSE);
break;
case FCIDM_SHVIEW_UNDO: case FCIDM_SHVIEW_UNDO:
Result = DoUndo(&LocalInvokeInfo); Result = DoUndo(&LocalInvokeInfo);
break; break;
+2 -2
View File
@@ -9,7 +9,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell); WINE_DEFAULT_DEBUG_CHANNEL(shell);
HRESULT EXTERN_C HRESULT
SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId) SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId)
{ {
// First try the key name // First try the key name
@@ -22,7 +22,7 @@ SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId)
return !err ? SHCLSIDFromStringW(buf, pClsId) : HRESULT_FROM_WIN32(err); return !err ? SHCLSIDFromStringW(buf, pClsId) : HRESULT_FROM_WIN32(err);
} }
static HRESULT EXTERN_C HRESULT
SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDO, HKEY hkeyProgID, REFIID riid, void **ppv) SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDO, HKEY hkeyProgID, REFIID riid, void **ppv)
{ {
*ppv = NULL; *ppv = NULL;
+19 -10
View File
@@ -1831,7 +1831,6 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
return hr; return hr;
CComHeapPtr<char> verb, parameters, dir; CComHeapPtr<char> verb, parameters, dir;
__SHCloneStrWtoA(&verb, sei->lpVerb);
__SHCloneStrWtoA(&parameters, sei->lpParameters); __SHCloneStrWtoA(&parameters, sei->lpParameters);
__SHCloneStrWtoA(&dir, sei->lpDirectory); __SHCloneStrWtoA(&dir, sei->lpDirectory);
@@ -1841,6 +1840,7 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
ici.nShow = sei->nShow; ici.nShow = sei->nShow;
if (!fDefault) if (!fDefault)
{ {
__SHCloneStrWtoA(&verb, sei->lpVerb);
ici.lpVerb = verb; ici.lpVerb = verb;
ici.lpVerbW = sei->lpVerb; ici.lpVerbW = sei->lpVerb;
} }
@@ -2185,6 +2185,19 @@ static void do_error_dialog(UINT_PTR retval, HWND hwnd, PCWSTR filename)
SetLastError(error_code); // Restore SetLastError(error_code); // Restore
} }
static UINT_PTR ExecuteFailed(UINT_PTR retval, SHELLEXECUTEINFOW &sei, LPCWSTR lpFile, BOOL AllowOpenWith = TRUE)
{
if (retval <= 32 && !(sei.fMask & SEE_MASK_FLAG_NO_UI))
{
if (retval == SE_ERR_NOASSOC && !(sei.fMask & SEE_MASK_CLASSALL) && AllowOpenWith)
retval = InvokeOpenWith(sei.hwnd, sei);
if (retval <= 32)
do_error_dialog(retval, sei.hwnd, lpFile);
}
sei.hInstApp = (HINSTANCE)UlongToHandle(retval > 32 ? 33 : retval);
return retval;
}
static WCHAR *expand_environment( const WCHAR *str ) static WCHAR *expand_environment( const WCHAR *str )
{ {
CHeapPtr<WCHAR, CLocalAllocator> buf; CHeapPtr<WCHAR, CLocalAllocator> buf;
@@ -2351,8 +2364,7 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
} }
/* process the IDList */ /* process the IDList */
if (sei_tmp.fMask & SEE_MASK_IDLIST && if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_IDLIST)
(sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST)
{ {
LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList; LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList;
hr = SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszApplicationName, dwApplicationNameLen, NULL); hr = SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszApplicationName, dwApplicationNameLen, NULL);
@@ -2385,6 +2397,9 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
sei->hInstApp = (HINSTANCE)42; sei->hInstApp = (HINSTANCE)42;
return TRUE; return TRUE;
} }
UINT err = HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : GetLastError();
SetLastError(err ? err : ERROR_ACCESS_DENIED);
return ExecuteFailed(retval, *sei, NULL, FALSE) > 32;
} }
if (ERROR_SUCCESS == ShellExecute_FromContextMenuHandlers(&sei_tmp)) if (ERROR_SUCCESS == ShellExecute_FromContextMenuHandlers(&sei_tmp))
@@ -2588,16 +2603,10 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
TRACE("retval %lu\n", retval); TRACE("retval %lu\n", retval);
if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
{
if (retval == SE_ERR_NOASSOC && !(sei->fMask & SEE_MASK_CLASSALL))
retval = InvokeOpenWith(sei_tmp.hwnd, *sei);
if (retval <= 32) if (retval <= 32)
do_error_dialog(retval, sei_tmp.hwnd, lpFile); retval = ExecuteFailed(retval, *sei, lpFile);
}
sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval); sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
return retval > 32; return retval > 32;
} }
+5 -4
View File
@@ -165,10 +165,11 @@ HGLOBAL RenderSHELLIDLIST (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cid
HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN; HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN; HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
HRESULT SHELL_GetShellExtensionRegCLSID( EXTERN_C HRESULT
HKEY hKey, SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId);
LPCWSTR KeyName, EXTERN_C HRESULT
CLSID *pClsId); SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDO,
HKEY hkeyProgID, REFIID riid, void **ppv);
/* Change Notification */ /* Change Notification */
void InitChangeNotifications(void) DECLSPEC_HIDDEN; void InitChangeNotifications(void) DECLSPEC_HIDDEN;
@@ -46,7 +46,7 @@ list(APPEND SOURCE
She.cpp She.cpp
#ShellExec_RunDLL.cpp # Broke on Windows #ShellExec_RunDLL.cpp # Broke on Windows
#ShellExecCmdLine.cpp # Broke on Windows #ShellExecCmdLine.cpp # Broke on Windows
#ShellExecuteEx.cpp # Broke on Windows ShellExecuteEx.cpp
#ShellExecuteW.cpp # Broke on Windows #ShellExecuteW.cpp # Broke on Windows
ShellHook.cpp ShellHook.cpp
ShellInfo.cpp ShellInfo.cpp
@@ -17,6 +17,27 @@
#include <shellutils.h> #include <shellutils.h>
#include "shell32_apitest_sub.h" #include "shell32_apitest_sub.h"
static void RunTest(LPTHREAD_START_ROUTINE TestFunc, UINT TimeOut = 1000 * 30)
{
// These tests have a tendency to hang, kill it if it takes too long
HANDLE hThread = CreateThread(NULL, 0, TestFunc, NULL, 0, NULL);
if (hThread)
{
if (WaitForSingleObject(hThread, TimeOut) != WAIT_OBJECT_0)
TerminateThread(hThread, ERROR_OPERATION_ABORTED);
CloseHandle(hThread);
}
}
template<class T> static T& Reset(T &sei, UINT flags = SEE_MASK_FLAG_NO_UI)
{
ZeroMemory(&sei, sizeof(T));
sei.cbSize = sizeof(T);
sei.fMask = flags;
sei.nShow = SW_SHOW;
return sei;
}
static WCHAR s_win_dir[MAX_PATH]; static WCHAR s_win_dir[MAX_PATH];
static WCHAR s_sys_dir[MAX_PATH]; static WCHAR s_sys_dir[MAX_PATH];
static WCHAR s_win_notepad[MAX_PATH]; static WCHAR s_win_notepad[MAX_PATH];
@@ -511,8 +532,47 @@ static void test_DoInvalidDir(void)
CloseHandle(sei.hProcess); CloseHandle(sei.hProcess);
} }
static DWORD CALLBACK Test_InvokeIdList(LPVOID)
{
CCoInit ComInit;
UINT err, ret;
WCHAR Path[MAX_PATH * 2];
CComHeapPtr<ITEMIDLIST> pidl;
SHELLEXECUTEINFOW sei;
Reset(sei, SEE_MASK_FLAG_NO_UI | SEE_MASK_INVOKEIDLIST).nShow = SW_HIDE;
GetSystemDirectoryW(Path, _countof(Path));
PathAppendW(Path, L"cmd.exe");
sei.lpParameters = L"/C exit 0";
sei.lpIDList = LPITEMIDLIST((pidl.Attach(ILCreateFromPathW(Path)), pidl));
if (!pidl)
{
skip("No exe to test\n");
return 0;
}
sei.lpVerb = NULL;
ok(ShellExecuteExW(&sei), "Failed with error %lu\n", GetLastError());
sei.lpVerb = L"open";
ok(ShellExecuteExW(&sei), "Failed with error %lu\n", GetLastError());
sei.lpVerb = L"Shell32_Test_DoesNotExist";
ret = ShellExecuteExW(&sei), err = GetLastError();
ok(!ret, "Expected failure\n");
ok_long(err, IsWindowsVistaOrGreater() ? ERROR_NO_ASSOCIATION : ERROR_INVALID_PARAMETER);
return 0;
}
START_TEST(ShellExecuteEx) START_TEST(ShellExecuteEx)
{ {
RunTest(Test_InvokeIdList);
// FIXME: These tests are broken (silent skip for now)
if (!lstrcmpiW(L"", L""))
return;
#ifdef _WIN64 #ifdef _WIN64
skip("Win64 is not supported yet\n"); skip("Win64 is not supported yet\n");
return; return;
+1 -1
View File
@@ -106,7 +106,7 @@ const struct test winetest_testlist[] =
{ "She", func_She }, { "She", func_She },
//{ "ShellExec_RunDLL", func_ShellExec_RunDLL }, Broke on Windows //{ "ShellExec_RunDLL", func_ShellExec_RunDLL }, Broke on Windows
//{ "ShellExecCmdLine", func_ShellExecCmdLine }, Broke on Windows //{ "ShellExecCmdLine", func_ShellExecCmdLine }, Broke on Windows
//{ "ShellExecuteEx", func_ShellExecuteEx }, Broke on Windows { "ShellExecuteEx", func_ShellExecuteEx }, // Mostly broken on Windows, only simple tests enabled
//{ "ShellExecuteW", func_ShellExecuteW }, Broke on Windows //{ "ShellExecuteW", func_ShellExecuteW }, Broke on Windows
{ "ShellHook", func_ShellHook }, { "ShellHook", func_ShellHook },
{ "ShellState", func_ShellState }, { "ShellState", func_ShellState },