mirror of
https://github.com/reactos/reactos.git
synced 2025-06-10 12:24:48 +00:00
[SHELL32]
- Add support for canonical/string verbs when using CMINVOKECOMMANDINFO. This fixes switching views and adding a new folder when using the button in the common dialogs. This really needs to go in a CDefFolderMenu class (which likely inherits the context menu class), but we don't use that design. - Partially implement CDefaultContextMenu::GetCommandString 'while I was there' It's completely untested though. CORE-10089 svn path=/trunk/; revision=70215
This commit is contained in:
parent
51c131bcb5
commit
e828ff57bc
3 changed files with 240 additions and 43 deletions
|
@ -14,6 +14,13 @@ TODO:
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
//fixme: this isn't in wine's shlwapi header, and the definition doesnt match the
|
||||||
|
// windows headers. When wine's header and lib are fixed this can be removed.
|
||||||
|
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen);
|
||||||
|
};
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
||||||
|
|
||||||
typedef struct _DynamicShellEntry_
|
typedef struct _DynamicShellEntry_
|
||||||
|
@ -32,6 +39,26 @@ typedef struct _StaticShellEntry_
|
||||||
struct _StaticShellEntry_ *pNext;
|
struct _StaticShellEntry_ *pNext;
|
||||||
} StaticShellEntry, *PStaticShellEntry;
|
} StaticShellEntry, *PStaticShellEntry;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// verbs for InvokeCommandInfo
|
||||||
|
//
|
||||||
|
struct _StaticInvokeCommandMap_
|
||||||
|
{
|
||||||
|
LPCSTR szStringVerb;
|
||||||
|
UINT IntVerb;
|
||||||
|
} g_StaticInvokeCmdMap[] =
|
||||||
|
{
|
||||||
|
{ "RunAs", 0 }, // Unimplemented
|
||||||
|
{ "Print", 0 }, // Unimplemented
|
||||||
|
{ "Preview", 0 }, // Unimplemented
|
||||||
|
{ "Open", FCIDM_SHVIEW_OPEN },
|
||||||
|
{ CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER },
|
||||||
|
{ CMDSTR_VIEWLISTA, FCIDM_SHVIEW_LISTVIEW },
|
||||||
|
{ CMDSTR_VIEWDETAILSA, FCIDM_SHVIEW_REPORTVIEW }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class CDefaultContextMenu :
|
class CDefaultContextMenu :
|
||||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
public IContextMenu3
|
public IContextMenu3
|
||||||
|
@ -69,12 +96,14 @@ class CDefaultContextMenu :
|
||||||
HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
|
HRESULT DoCreateNewFolder(LPCMINVOKECOMMANDINFO lpici);
|
||||||
HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
|
||||||
DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
|
DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
|
||||||
HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
|
HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
|
||||||
HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
|
HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
|
||||||
PDynamicShellEntry GetDynamicEntry(UINT idCmd);
|
PDynamicShellEntry GetDynamicEntry(UINT idCmd);
|
||||||
|
BOOL MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDefaultContextMenu();
|
CDefaultContextMenu();
|
||||||
|
@ -1367,6 +1396,67 @@ CDefaultContextMenu::DoFormat(
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This code is taken from CNewMenu and should be shared between the 2 classes
|
||||||
|
HRESULT
|
||||||
|
CDefaultContextMenu::DoCreateNewFolder(
|
||||||
|
LPCMINVOKECOMMANDINFO lpici)
|
||||||
|
{
|
||||||
|
WCHAR wszPath[MAX_PATH];
|
||||||
|
WCHAR wszName[MAX_PATH];
|
||||||
|
WCHAR wszNewFolder[25];
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
/* Get folder path */
|
||||||
|
hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder)))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
/* Create the name of the new directory */
|
||||||
|
if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
/* Create the new directory and show the appropriate dialog in case of error */
|
||||||
|
if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
/* Show and select the new item in the def view */
|
||||||
|
CComPtr<IShellBrowser> lpSB;
|
||||||
|
CComPtr<IShellView> lpSV;
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
PITEMID_CHILD pidlNewItem;
|
||||||
|
|
||||||
|
/* Notify the view object about the new item */
|
||||||
|
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, (LPCVOID)wszName, NULL);
|
||||||
|
|
||||||
|
/* FIXME: I think that this can be implemented using callbacks to the shell folder */
|
||||||
|
|
||||||
|
/* Note: CWM_GETISHELLBROWSER returns shell browser without adding reference */
|
||||||
|
lpSB = (LPSHELLBROWSER)SendMessageA(lpici->hwnd, CWM_GETISHELLBROWSER, 0, 0);
|
||||||
|
if (!lpSB)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
hr = lpSB->QueryActiveShellView(&lpSV);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
/* Attempt to get the pidl of the new item */
|
||||||
|
hr = SHILCreateFromPathW(wszName, &pidl, NULL);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
pidlNewItem = ILFindLastID(pidl);
|
||||||
|
|
||||||
|
hr = lpSV->SelectItem(pidlNewItem, SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE |
|
||||||
|
SVSI_FOCUSED | SVSI_SELECT);
|
||||||
|
|
||||||
|
SHFree(pidl);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
|
PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
|
||||||
{
|
{
|
||||||
PDynamicShellEntry pEntry = m_pDynamicEntries;
|
PDynamicShellEntry pEntry = m_pDynamicEntries;
|
||||||
|
@ -1383,6 +1473,42 @@ PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
||||||
|
#define MAX_VERB 260
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
||||||
|
{
|
||||||
|
WCHAR UnicodeStr[MAX_VERB];
|
||||||
|
|
||||||
|
/* Loop through all the static verbs looking for a match */
|
||||||
|
for (UINT 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 (!wcscmp(UnicodeStr, (LPWSTR)Verb))
|
||||||
|
{
|
||||||
|
/* Return the Corresponding Id */
|
||||||
|
*idCmd = g_StaticInvokeCmdMap[i].IntVerb;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!strcmp(g_StaticInvokeCmdMap[i].szStringVerb, (LPSTR)Verb))
|
||||||
|
{
|
||||||
|
*idCmd = g_StaticInvokeCmdMap[i].IntVerb;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
CDefaultContextMenu::DoDynamicShellExtensions(
|
CDefaultContextMenu::DoDynamicShellExtensions(
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
LPCMINVOKECOMMANDINFO lpcmi)
|
||||||
|
@ -1549,57 +1675,97 @@ WINAPI
|
||||||
CDefaultContextMenu::InvokeCommand(
|
CDefaultContextMenu::InvokeCommand(
|
||||||
LPCMINVOKECOMMANDINFO lpcmi)
|
LPCMINVOKECOMMANDINFO lpcmi)
|
||||||
{
|
{
|
||||||
switch(LOWORD(lpcmi->lpVerb))
|
CMINVOKECOMMANDINFO LocalInvokeInfo;
|
||||||
|
HRESULT Result;
|
||||||
|
UINT CmdId;
|
||||||
|
|
||||||
|
/* Take a local copy of the fixed members of the
|
||||||
|
struct as we might need to modify the verb */
|
||||||
|
LocalInvokeInfo = *lpcmi;
|
||||||
|
|
||||||
|
/* Check if this is a string verb */
|
||||||
|
if (HIWORD(LocalInvokeInfo.lpVerb))
|
||||||
{
|
{
|
||||||
case FCIDM_SHVIEW_BIGICON:
|
/* Get the ID which corresponds to this verb, and update our local copy */
|
||||||
case FCIDM_SHVIEW_SMALLICON:
|
if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE))
|
||||||
case FCIDM_SHVIEW_LISTVIEW:
|
LocalInvokeInfo.lpVerb = MAKEINTRESOURCEA(CmdId);
|
||||||
case FCIDM_SHVIEW_REPORTVIEW:
|
|
||||||
case 0x30: /* FIX IDS in resource files */
|
|
||||||
case 0x31:
|
|
||||||
case 0x32:
|
|
||||||
case 0x33:
|
|
||||||
case FCIDM_SHVIEW_AUTOARRANGE:
|
|
||||||
case FCIDM_SHVIEW_SNAPTOGRID:
|
|
||||||
return NotifyShellViewWindow(lpcmi, FALSE);
|
|
||||||
case FCIDM_SHVIEW_REFRESH:
|
|
||||||
return DoRefresh(lpcmi);
|
|
||||||
case FCIDM_SHVIEW_INSERT:
|
|
||||||
return DoPaste(lpcmi, FALSE);
|
|
||||||
case FCIDM_SHVIEW_INSERTLINK:
|
|
||||||
return DoPaste(lpcmi, TRUE);
|
|
||||||
case FCIDM_SHVIEW_OPEN:
|
|
||||||
case FCIDM_SHVIEW_EXPLORE:
|
|
||||||
return DoOpenOrExplore(lpcmi);
|
|
||||||
case FCIDM_SHVIEW_COPY:
|
|
||||||
case FCIDM_SHVIEW_CUT:
|
|
||||||
return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
|
|
||||||
case FCIDM_SHVIEW_CREATELINK:
|
|
||||||
return DoCreateLink(lpcmi);
|
|
||||||
case FCIDM_SHVIEW_DELETE:
|
|
||||||
return DoDelete(lpcmi);
|
|
||||||
case FCIDM_SHVIEW_RENAME:
|
|
||||||
return DoRename(lpcmi);
|
|
||||||
case FCIDM_SHVIEW_PROPERTIES:
|
|
||||||
return DoProperties(lpcmi);
|
|
||||||
case 0x7ABC:
|
|
||||||
return DoFormat(lpcmi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_iIdSHEFirst && m_iIdSHELast)
|
/* Check if this is a Id */
|
||||||
|
switch (LOWORD(LocalInvokeInfo.lpVerb))
|
||||||
{
|
{
|
||||||
if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
|
case FCIDM_SHVIEW_BIGICON:
|
||||||
return DoDynamicShellExtensions(lpcmi);
|
case FCIDM_SHVIEW_SMALLICON:
|
||||||
|
case FCIDM_SHVIEW_LISTVIEW:
|
||||||
|
case FCIDM_SHVIEW_REPORTVIEW:
|
||||||
|
case 0x30: /* FIX IDS in resource files */
|
||||||
|
case 0x31:
|
||||||
|
case 0x32:
|
||||||
|
case 0x33:
|
||||||
|
case FCIDM_SHVIEW_AUTOARRANGE:
|
||||||
|
case FCIDM_SHVIEW_SNAPTOGRID:
|
||||||
|
Result = NotifyShellViewWindow(&LocalInvokeInfo, FALSE);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_REFRESH:
|
||||||
|
Result = DoRefresh(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_INSERT:
|
||||||
|
Result = DoPaste(&LocalInvokeInfo, FALSE);
|
||||||
|
break;
|
||||||
|
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, LOWORD(LocalInvokeInfo.lpVerb) == FCIDM_SHVIEW_COPY);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_CREATELINK:
|
||||||
|
Result = DoCreateLink(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_DELETE:
|
||||||
|
Result = DoDelete(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_RENAME:
|
||||||
|
Result = DoRename(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_PROPERTIES:
|
||||||
|
Result = DoProperties(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case 0x7ABC:
|
||||||
|
Result = DoFormat(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
case FCIDM_SHVIEW_NEWFOLDER:
|
||||||
|
Result = DoCreateNewFolder(&LocalInvokeInfo);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Result = E_UNEXPECTED;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_iIdSCMFirst && m_iIdSCMLast)
|
/* Check for ID's we didn't find a handler for */
|
||||||
|
if (Result == E_UNEXPECTED)
|
||||||
{
|
{
|
||||||
if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
|
if (m_iIdSHEFirst && m_iIdSHELast)
|
||||||
return DoStaticShellExtensions(lpcmi);
|
{
|
||||||
|
if (LOWORD(LocalInvokeInfo.lpVerb) >= m_iIdSHEFirst && LOWORD(LocalInvokeInfo.lpVerb) <= m_iIdSHELast)
|
||||||
|
Result = DoDynamicShellExtensions(&LocalInvokeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_iIdSCMFirst && m_iIdSCMLast)
|
||||||
|
{
|
||||||
|
if (LOWORD(LocalInvokeInfo.lpVerb) >= m_iIdSCMFirst && LOWORD(LocalInvokeInfo.lpVerb) <= m_iIdSCMLast)
|
||||||
|
Result = DoStaticShellExtensions(&LocalInvokeInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
|
if (Result == E_UNEXPECTED)
|
||||||
return E_UNEXPECTED;
|
FIXME("Unhandled Verb %xl\n", LOWORD(LocalInvokeInfo.lpVerb));
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
@ -1611,7 +1777,36 @@ CDefaultContextMenu::GetCommandString(
|
||||||
LPSTR lpszName,
|
LPSTR lpszName,
|
||||||
UINT uMaxNameLen)
|
UINT uMaxNameLen)
|
||||||
{
|
{
|
||||||
return S_OK;
|
/* We don't handle the help text yet */
|
||||||
|
if (uFlags == GCS_HELPTEXTA ||
|
||||||
|
uFlags == GCS_HELPTEXTW)
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop looking for a matching Id */
|
||||||
|
for (UINT i = 0; i < _countof(g_StaticInvokeCmdMap); i++)
|
||||||
|
{
|
||||||
|
if (g_StaticInvokeCmdMap[i].IntVerb == idCommand)
|
||||||
|
{
|
||||||
|
/* Validation just returns S_OK on a match */
|
||||||
|
if (uFlags == GCS_VALIDATEA || uFlags == GCS_VALIDATEA)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
/* Return a copy of the ANSI verb */
|
||||||
|
if (uFlags == GCS_VERBA)
|
||||||
|
return StringCchCopyA(lpszName, uMaxNameLen, g_StaticInvokeCmdMap[i].szStringVerb);
|
||||||
|
|
||||||
|
/* Convert the ANSI verb to unicode and return that */
|
||||||
|
if (uFlags == GCS_VERBW)
|
||||||
|
{
|
||||||
|
if (SHAnsiToUnicode(g_StaticInvokeCmdMap[i].szStringVerb, (LPWSTR)lpszName, uMaxNameLen))
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
|
@ -337,6 +337,7 @@ HRESULT CNewMenu::SelectNewItem(LPCMINVOKECOMMANDINFO lpici, LONG wEventId, UINT
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Code is duplicated in CDefaultContextMenu
|
||||||
HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
|
HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
|
||||||
{
|
{
|
||||||
WCHAR wszPath[MAX_PATH];
|
WCHAR wszPath[MAX_PATH];
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <ddeml.h>
|
#include <ddeml.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
#include <recyclebin.h>
|
#include <recyclebin.h>
|
||||||
#include <ndk/rtlfuncs.h>
|
#include <ndk/rtlfuncs.h>
|
||||||
#include <fmifs/fmifs.h>
|
#include <fmifs/fmifs.h>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue