mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[SHELL32][SHELL32_APITEST] Handle named registry verbs in CDefaultContextMenu::InvokeCommand (#9340)
CORE-20690
This commit is contained in:
@@ -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
|
||||
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
|
||||
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
CCopyMoveToMenu *this_ =
|
||||
reinterpret_cast<CCopyMoveToMenu *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
CCopyMoveToMenu *this_ = reinterpret_cast<CCopyMoveToMenu*>(lpData);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
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
|
||||
CString strCaption(MAKEINTRESOURCEW(this_->GetCaptionStringID()));
|
||||
SetWindowTextW(hwnd, strCaption);
|
||||
@@ -85,31 +90,30 @@ BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
SetDlgItemText(hwnd, IDOK, strCopyOrMove);
|
||||
|
||||
// Subclassing
|
||||
// TODO: Replace this with BIF_VALIDATE
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, lpData);
|
||||
this_->m_fnOldWndProc =
|
||||
reinterpret_cast<WNDPROC>(
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc)));
|
||||
|
||||
// Disable OK
|
||||
PostMessageW(hwnd, BFFM_ENABLEOK, 0, FALSE);
|
||||
// Expand "My Computer"
|
||||
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;
|
||||
}
|
||||
case BFFM_SELCHANGED:
|
||||
{
|
||||
if (!this_)
|
||||
break;
|
||||
|
||||
WCHAR szPath[MAX_PATH];
|
||||
LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(lParam);
|
||||
|
||||
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);
|
||||
PostMessageW(hwnd, BFFM_ENABLEOK, 0, IsValidTarget(this_, pidl));
|
||||
|
||||
// the text box will be updated later soon, ignore it
|
||||
this_->m_bIgnoreTextBoxChange = TRUE;
|
||||
@@ -123,6 +127,7 @@ BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
HRESULT
|
||||
CCopyMoveToMenu::DoRealFileOp(const CIDA *pCIDA, LPCMINVOKECOMMANDINFO lpici, PCUIDLIST_ABSOLUTE pidlDestination)
|
||||
{
|
||||
// TODO: Use SH32_SimulateDropWithSite instead
|
||||
CStringW strFiles;
|
||||
WCHAR szPath[MAX_PATH];
|
||||
for (UINT n = 0; n < pCIDA->cidl; ++n)
|
||||
@@ -340,15 +345,13 @@ CCopyMoveToMenu::GetCommandString(
|
||||
LPSTR pszName,
|
||||
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)
|
||||
return idCmd == IDC_ACTION ? S_OK : S_FALSE;
|
||||
|
||||
if (uType == GCS_VERBW && idCmd == IDC_ACTION)
|
||||
return SHAnsiToUnicode(GetVerb(), (LPWSTR)pszName, cchMax);
|
||||
|
||||
FIXME("%p %lu %u %p %p %u\n", this,
|
||||
idCmd, uType, pwReserved, pszName, cchMax);
|
||||
|
||||
#endif
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
@@ -398,3 +401,30 @@ CCopyMoveToMenu::GetSite(REFIID riid, void **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);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ public:
|
||||
// IObjectWithSite
|
||||
STDMETHODIMP SetSite(IUnknown *pUnkSite) 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
|
||||
|
||||
@@ -2487,25 +2487,9 @@ void CDefView::DoActivate(UINT uState)
|
||||
|
||||
void CDefView::_DoCopyToMoveToFolder(BOOL bCopy)
|
||||
{
|
||||
if (!GetSelections())
|
||||
return;
|
||||
|
||||
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);
|
||||
if (GetSelections())
|
||||
CCopyMoveToMenu::DoCopyMoveToFolder(bCopy, m_hWnd, static_cast<IDropTarget*>(this),
|
||||
m_pSFParent, m_cidl, m_apidl);
|
||||
}
|
||||
|
||||
LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
||||
|
||||
@@ -164,10 +164,7 @@ static const struct _StaticInvokeCommandMap_
|
||||
SHORT DfmCmd;
|
||||
} g_StaticInvokeCmdMap[] =
|
||||
{
|
||||
{ "runas", 0 }, // Unimplemented
|
||||
{ "print", 0 }, // Unimplemented
|
||||
{ "preview", 0 }, // Unimplemented
|
||||
{ "open", FCIDM_SHVIEW_OPEN },
|
||||
// Note: Verbs from the registry should not be listed here
|
||||
{ CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER, (SHORT)DFM_CMD_NEWFOLDER },
|
||||
{ "cut", FCIDM_SHVIEW_CUT, /* ? */ },
|
||||
{ "copy", FCIDM_SHVIEW_COPY, (SHORT)DFM_CMD_COPY },
|
||||
@@ -176,8 +173,6 @@ static const struct _StaticInvokeCommandMap_
|
||||
{ "delete", FCIDM_SHVIEW_DELETE, (SHORT)DFM_CMD_DELETE },
|
||||
{ "properties", FCIDM_SHVIEW_PROPERTIES, (SHORT)DFM_CMD_PROPERTIES },
|
||||
{ "rename", FCIDM_SHVIEW_RENAME, (SHORT)DFM_CMD_RENAME },
|
||||
{ "copyto", FCIDM_SHVIEW_COPYTO },
|
||||
{ "moveto", FCIDM_SHVIEW_MOVETO },
|
||||
};
|
||||
|
||||
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 AddStaticContextMenusToMenu(HMENU hMenu, UINT* IndexMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
|
||||
HRESULT DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink);
|
||||
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT DoDelete(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bCopy);
|
||||
@@ -336,7 +330,6 @@ class CDefaultContextMenu :
|
||||
HRESULT DoProperties(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT DoUndo(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT DoCreateNewFolder(LPCMINVOKECOMMANDINFOEX lpici);
|
||||
HRESULT DoCopyToMoveToFolder(LPCMINVOKECOMMANDINFOEX lpici, BOOL bCopy);
|
||||
HRESULT InvokeShellExt(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
HRESULT InvokeRegVerb(LPCMINVOKECOMMANDINFOEX lpcmi);
|
||||
DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStaticShellEntry pEntry);
|
||||
@@ -345,6 +338,11 @@ class CDefaultContextMenu :
|
||||
PDynamicShellEntry GetDynamicEntry(UINT idCmd);
|
||||
BOOL MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode);
|
||||
|
||||
HRESULT GetNoAssocError()
|
||||
{
|
||||
return LOBYTE(GetVersion()) < 6 ? E_INVALIDARG : HResultFromWin32(ERROR_NO_ASSOCIATION);
|
||||
}
|
||||
|
||||
public:
|
||||
CDefaultContextMenu();
|
||||
~CDefaultContextMenu();
|
||||
@@ -1108,13 +1106,6 @@ HRESULT CDefaultContextMenu::DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
CDefaultContextMenu::DoOpenOrExplore(LPCMINVOKECOMMANDINFOEX lpcmi)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi)
|
||||
{
|
||||
HRESULT hr = _DoInvokeCommandCallback(lpcmi, DFM_CMD_LINK);
|
||||
@@ -1239,43 +1230,6 @@ CDefaultContextMenu::DoUndo(LPCMINVOKECOMMANDINFOEX lpcmi)
|
||||
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
|
||||
HRESULT
|
||||
CDefaultContextMenu::DoCreateNewFolder(
|
||||
@@ -1358,18 +1312,16 @@ BOOL
|
||||
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
||||
{
|
||||
WCHAR UnicodeStr[MAX_VERB];
|
||||
UINT i;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* The static verbs are ANSI, get a unicode version before doing the compare */
|
||||
SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, UnicodeStr, MAX_VERB);
|
||||
if (!_wcsicmp(UnicodeStr, (LPWSTR)Verb))
|
||||
{
|
||||
/* Return the Corresponding Id */
|
||||
*idCmd = g_StaticInvokeCmdMap[i].IntVerb;
|
||||
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);
|
||||
if (!entry.NumIds)
|
||||
@@ -1396,7 +1363,7 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return FALSE; // Note: Even if the verb is "open", we must fail if we can't find a handler
|
||||
}
|
||||
|
||||
HRESULT
|
||||
@@ -1547,7 +1514,7 @@ CDefaultContextMenu::InvokeRegVerb(
|
||||
POSITION it = m_StaticEntries.FindIndex(iCmd);
|
||||
|
||||
if (it == NULL)
|
||||
return E_INVALIDARG;
|
||||
return HResultFromWin32(ERROR_NO_ASSOCIATION);
|
||||
|
||||
PStaticShellEntry pEntry = &m_StaticEntries.GetAt(it);
|
||||
|
||||
@@ -1670,7 +1637,7 @@ CDefaultContextMenu::InvokeCommand(
|
||||
if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE))
|
||||
LocalInvokeInfo.lpVerb = MAKEINTRESOURCEA(CmdId);
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
return GetNoAssocError();
|
||||
}
|
||||
CmdId = LOWORD(LocalInvokeInfo.lpVerb);
|
||||
|
||||
@@ -1719,10 +1686,6 @@ CDefaultContextMenu::InvokeCommand(
|
||||
case FCIDM_SHVIEW_INSERTLINK:
|
||||
Result = DoPaste(&LocalInvokeInfo, TRUE);
|
||||
break;
|
||||
case FCIDM_SHVIEW_OPEN:
|
||||
case FCIDM_SHVIEW_EXPLORE:
|
||||
Result = DoOpenOrExplore(&LocalInvokeInfo);
|
||||
break;
|
||||
case FCIDM_SHVIEW_COPY:
|
||||
case FCIDM_SHVIEW_CUT:
|
||||
Result = DoCopyOrCut(&LocalInvokeInfo, CmdId == FCIDM_SHVIEW_COPY);
|
||||
@@ -1742,12 +1705,6 @@ CDefaultContextMenu::InvokeCommand(
|
||||
case FCIDM_SHVIEW_NEWFOLDER:
|
||||
Result = DoCreateNewFolder(&LocalInvokeInfo);
|
||||
break;
|
||||
case FCIDM_SHVIEW_COPYTO:
|
||||
Result = DoCopyToMoveToFolder(&LocalInvokeInfo, TRUE);
|
||||
break;
|
||||
case FCIDM_SHVIEW_MOVETO:
|
||||
Result = DoCopyToMoveToFolder(&LocalInvokeInfo, FALSE);
|
||||
break;
|
||||
case FCIDM_SHVIEW_UNDO:
|
||||
Result = DoUndo(&LocalInvokeInfo);
|
||||
break;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
|
||||
HRESULT
|
||||
EXTERN_C HRESULT
|
||||
SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
EXTERN_C HRESULT
|
||||
SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDO, HKEY hkeyProgID, REFIID riid, void **ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
|
||||
@@ -1831,7 +1831,6 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
|
||||
return hr;
|
||||
|
||||
CComHeapPtr<char> verb, parameters, dir;
|
||||
__SHCloneStrWtoA(&verb, sei->lpVerb);
|
||||
__SHCloneStrWtoA(¶meters, sei->lpParameters);
|
||||
__SHCloneStrWtoA(&dir, sei->lpDirectory);
|
||||
|
||||
@@ -1841,6 +1840,7 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
|
||||
ici.nShow = sei->nShow;
|
||||
if (!fDefault)
|
||||
{
|
||||
__SHCloneStrWtoA(&verb, sei->lpVerb);
|
||||
ici.lpVerb = verb;
|
||||
ici.lpVerbW = sei->lpVerb;
|
||||
}
|
||||
@@ -2185,6 +2185,19 @@ static void do_error_dialog(UINT_PTR retval, HWND hwnd, PCWSTR filename)
|
||||
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 )
|
||||
{
|
||||
CHeapPtr<WCHAR, CLocalAllocator> buf;
|
||||
@@ -2351,8 +2364,7 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
|
||||
}
|
||||
|
||||
/* process the IDList */
|
||||
if (sei_tmp.fMask & SEE_MASK_IDLIST &&
|
||||
(sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST)
|
||||
if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_IDLIST)
|
||||
{
|
||||
LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList;
|
||||
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;
|
||||
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))
|
||||
@@ -2588,16 +2603,10 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
|
||||
|
||||
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)
|
||||
do_error_dialog(retval, sei_tmp.hwnd, lpFile);
|
||||
}
|
||||
if (retval <= 32)
|
||||
retval = ExecuteFailed(retval, *sei, lpFile);
|
||||
|
||||
sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
|
||||
|
||||
return retval > 32;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,10 +165,11 @@ HGLOBAL RenderSHELLIDLIST (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cid
|
||||
HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
|
||||
HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT SHELL_GetShellExtensionRegCLSID(
|
||||
HKEY hKey,
|
||||
LPCWSTR KeyName,
|
||||
CLSID *pClsId);
|
||||
EXTERN_C HRESULT
|
||||
SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId);
|
||||
EXTERN_C HRESULT
|
||||
SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDO,
|
||||
HKEY hkeyProgID, REFIID riid, void **ppv);
|
||||
|
||||
/* Change Notification */
|
||||
void InitChangeNotifications(void) DECLSPEC_HIDDEN;
|
||||
|
||||
@@ -46,7 +46,7 @@ list(APPEND SOURCE
|
||||
She.cpp
|
||||
#ShellExec_RunDLL.cpp # Broke on Windows
|
||||
#ShellExecCmdLine.cpp # Broke on Windows
|
||||
#ShellExecuteEx.cpp # Broke on Windows
|
||||
ShellExecuteEx.cpp
|
||||
#ShellExecuteW.cpp # Broke on Windows
|
||||
ShellHook.cpp
|
||||
ShellInfo.cpp
|
||||
|
||||
@@ -17,6 +17,27 @@
|
||||
#include <shellutils.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_sys_dir[MAX_PATH];
|
||||
static WCHAR s_win_notepad[MAX_PATH];
|
||||
@@ -511,8 +532,47 @@ static void test_DoInvalidDir(void)
|
||||
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)
|
||||
{
|
||||
RunTest(Test_InvokeIdList);
|
||||
|
||||
// FIXME: These tests are broken (silent skip for now)
|
||||
if (!lstrcmpiW(L"", L""))
|
||||
return;
|
||||
|
||||
#ifdef _WIN64
|
||||
skip("Win64 is not supported yet\n");
|
||||
return;
|
||||
|
||||
@@ -106,7 +106,7 @@ const struct test winetest_testlist[] =
|
||||
{ "She", func_She },
|
||||
//{ "ShellExec_RunDLL", func_ShellExec_RunDLL }, 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
|
||||
{ "ShellHook", func_ShellHook },
|
||||
{ "ShellState", func_ShellState },
|
||||
|
||||
Reference in New Issue
Block a user