|
@@ -22,13 +22,8 @@
|
|
|
#include <shellapi.h>
|
|
#include <shellapi.h>
|
|
|
#include <StringUtil.h>
|
|
#include <StringUtil.h>
|
|
|
|
|
|
|
|
-extern HINSTANCE g_hInst;
|
|
|
|
|
extern long g_cDllRef;
|
|
extern long g_cDllRef;
|
|
|
|
|
|
|
|
-#define IDM_SHARE 0
|
|
|
|
|
-#define IDM_COPYLINK 1
|
|
|
|
|
-#define IDM_EMAILLINK 2
|
|
|
|
|
-
|
|
|
|
|
OCContextMenu::OCContextMenu(void)
|
|
OCContextMenu::OCContextMenu(void)
|
|
|
: m_cRef(1)
|
|
: m_cRef(1)
|
|
|
{
|
|
{
|
|
@@ -40,23 +35,6 @@ OCContextMenu::~OCContextMenu(void)
|
|
|
InterlockedDecrement(&g_cDllRef);
|
|
InterlockedDecrement(&g_cDllRef);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-void OCContextMenu::OnVerbShare(HWND hWnd)
|
|
|
|
|
-{
|
|
|
|
|
- OCClientInterface::RequestShare(std::wstring(m_szSelectedFile));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void OCContextMenu::OnVerbCopyLink(HWND hWnd)
|
|
|
|
|
-{
|
|
|
|
|
- OCClientInterface::RequestCopyLink(std::wstring(m_szSelectedFile));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void OCContextMenu::OnVerbEmailLink(HWND hWnd)
|
|
|
|
|
-{
|
|
|
|
|
- OCClientInterface::RequestEmailLink(std::wstring(m_szSelectedFile));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
#pragma region IUnknown
|
|
#pragma region IUnknown
|
|
|
|
|
|
|
|
// Query to the interface the component supported.
|
|
// Query to the interface the component supported.
|
|
@@ -97,12 +75,12 @@ IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
|
|
IFACEMETHODIMP OCContextMenu::Initialize(
|
|
IFACEMETHODIMP OCContextMenu::Initialize(
|
|
|
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
|
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
|
|
{
|
|
{
|
|
|
|
|
+ m_selectedFiles.clear();
|
|
|
|
|
+
|
|
|
if (!pDataObj) {
|
|
if (!pDataObj) {
|
|
|
return E_INVALIDARG;
|
|
return E_INVALIDARG;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- HRESULT hr = E_FAIL;
|
|
|
|
|
-
|
|
|
|
|
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
|
STGMEDIUM stm;
|
|
STGMEDIUM stm;
|
|
|
|
|
|
|
@@ -110,14 +88,19 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
|
|
// Get an HDROP handle.
|
|
// Get an HDROP handle.
|
|
|
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
|
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
|
|
if (hDrop) {
|
|
if (hDrop) {
|
|
|
- // Ignore multi-selections
|
|
|
|
|
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
|
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
|
|
- if (nFiles == 1) {
|
|
|
|
|
|
|
+ for (int i = 0; i < nFiles; ++i) {
|
|
|
// Get the path of the file.
|
|
// Get the path of the file.
|
|
|
- if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
|
|
|
|
- {
|
|
|
|
|
- hr = S_OK;
|
|
|
|
|
|
|
+ wchar_t buffer[MAX_PATH];
|
|
|
|
|
+
|
|
|
|
|
+ if (!DragQueryFile(hDrop, i, buffer, ARRAYSIZE(buffer))) {
|
|
|
|
|
+ m_selectedFiles.clear();
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if (i)
|
|
|
|
|
+ m_selectedFiles += L'\x1e';
|
|
|
|
|
+ m_selectedFiles += buffer;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GlobalUnlock(stm.hGlobal);
|
|
GlobalUnlock(stm.hGlobal);
|
|
@@ -128,7 +111,7 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
|
|
|
|
|
|
|
// If any value other than S_OK is returned from the method, the context
|
|
// If any value other than S_OK is returned from the method, the context
|
|
|
// menu item is not displayed.
|
|
// menu item is not displayed.
|
|
|
- return hr;
|
|
|
|
|
|
|
+ return m_selectedFiles.empty() ? E_FAIL : S_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
#pragma endregion
|
|
@@ -153,17 +136,8 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
|
|
|
|
- bool skip = true;
|
|
|
|
|
- size_t selectedFileLength = wcslen(m_szSelectedFile);
|
|
|
|
|
- for (const std::wstring path : info.watchedDirectories) {
|
|
|
|
|
- if (StringUtil::isDescendantOf(m_szSelectedFile, selectedFileLength, path)) {
|
|
|
|
|
- skip = false;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (skip) {
|
|
|
|
|
|
|
+ m_info = OCClientInterface::FetchInfo(m_selectedFiles);
|
|
|
|
|
+ if (m_info.menuItems.empty()) {
|
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -175,7 +149,7 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
|
|
mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING;
|
|
mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING;
|
|
|
mii.hSubMenu = hSubmenu;
|
|
mii.hSubMenu = hSubmenu;
|
|
|
mii.fType = MFT_STRING;
|
|
mii.fType = MFT_STRING;
|
|
|
- mii.dwTypeData = &info.contextMenuTitle[0];
|
|
|
|
|
|
|
+ mii.dwTypeData = &m_info.contextMenuTitle[0];
|
|
|
|
|
|
|
|
if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii))
|
|
if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii))
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
@@ -183,133 +157,59 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
|
|
InsertSeperator(hMenu, indexMenu++);
|
|
InsertSeperator(hMenu, indexMenu++);
|
|
|
|
|
|
|
|
UINT indexSubMenu = 0;
|
|
UINT indexSubMenu = 0;
|
|
|
- {
|
|
|
|
|
- assert(!info.shareMenuTitle.empty());
|
|
|
|
|
- MENUITEMINFO mii = { sizeof(mii) };
|
|
|
|
|
- mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
|
|
|
|
- mii.wID = idCmdFirst + IDM_SHARE;
|
|
|
|
|
- mii.fType = MFT_STRING;
|
|
|
|
|
- mii.dwTypeData = &info.shareMenuTitle[0];
|
|
|
|
|
-
|
|
|
|
|
- if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
|
|
|
|
- return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
- }
|
|
|
|
|
- {
|
|
|
|
|
- assert(!info.copyLinkMenuTitle.empty());
|
|
|
|
|
- MENUITEMINFO mii = { sizeof(mii) };
|
|
|
|
|
- mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
|
|
|
|
- mii.wID = idCmdFirst + IDM_COPYLINK;
|
|
|
|
|
- mii.fType = MFT_STRING;
|
|
|
|
|
- mii.dwTypeData = &info.copyLinkMenuTitle[0];
|
|
|
|
|
|
|
+ for (auto &item : m_info.menuItems) {
|
|
|
|
|
+ bool disabled = item.flags.find(L'd') != std::string::npos;
|
|
|
|
|
|
|
|
- if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
|
|
|
|
- return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
- }
|
|
|
|
|
- {
|
|
|
|
|
- assert(!info.emailLinkMenuTitle.empty());
|
|
|
|
|
MENUITEMINFO mii = { sizeof(mii) };
|
|
MENUITEMINFO mii = { sizeof(mii) };
|
|
|
- mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
|
|
|
|
|
- mii.wID = idCmdFirst + IDM_EMAILLINK;
|
|
|
|
|
|
|
+ mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
|
|
|
|
|
+ mii.wID = indexSubMenu;
|
|
|
mii.fType = MFT_STRING;
|
|
mii.fType = MFT_STRING;
|
|
|
- mii.dwTypeData = &info.emailLinkMenuTitle[0];
|
|
|
|
|
|
|
+ mii.dwTypeData = &item.title[0];
|
|
|
|
|
+ mii.fState = disabled ? MFS_DISABLED : MFS_ENABLED;
|
|
|
|
|
|
|
|
- if (!InsertMenuItem(hSubmenu, indexSubMenu++, TRUE, &mii))
|
|
|
|
|
|
|
+ if (!InsertMenuItem(hSubmenu, indexSubMenu, true, &mii))
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
+ indexSubMenu++;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
|
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
|
|
// Set the code value to the offset of the largest command identifier
|
|
// Set the code value to the offset of the largest command identifier
|
|
|
// that was assigned, plus one (1).
|
|
// that was assigned, plus one (1).
|
|
|
- return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_EMAILLINK + 1));
|
|
|
|
|
|
|
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(indexSubMenu));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|
|
{
|
|
{
|
|
|
|
|
+ std::wstring command;
|
|
|
|
|
|
|
|
// For the Unicode case, if the high-order word is not zero, the
|
|
// For the Unicode case, if the high-order word is not zero, the
|
|
|
// command's verb string is in lpcmi->lpVerbW.
|
|
// command's verb string is in lpcmi->lpVerbW.
|
|
|
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
|
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
|
|
{
|
|
{
|
|
|
- // Is the verb supported by this context menu extension?
|
|
|
|
|
- if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocshare") == 0) {
|
|
|
|
|
- OnVerbShare(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"occopylink") == 0) {
|
|
|
|
|
- OnVerbCopyLink(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"ocemaillink") == 0) {
|
|
|
|
|
- OnVerbEmailLink(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // If the verb is not recognized by the context menu handler, it
|
|
|
|
|
- // must return E_FAIL to allow it to be passed on to the other
|
|
|
|
|
- // context menu handlers that might implement that verb.
|
|
|
|
|
- return E_FAIL;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ command = ((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // If the command cannot be identified through the verb string, then
|
|
|
|
|
+ // check the identifier offset.
|
|
|
|
|
|
|
|
- // If the command cannot be identified through the verb string, then
|
|
|
|
|
- // check the identifier offset.
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Is the command identifier offset supported by this context menu
|
|
|
|
|
- // extension?
|
|
|
|
|
- if (LOWORD(pici->lpVerb) == IDM_SHARE) {
|
|
|
|
|
- OnVerbShare(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else if (LOWORD(pici->lpVerb) == IDM_COPYLINK) {
|
|
|
|
|
- OnVerbCopyLink(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else if (LOWORD(pici->lpVerb) == IDM_EMAILLINK) {
|
|
|
|
|
- OnVerbEmailLink(pici->hwnd);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // If the verb is not recognized by the context menu handler, it
|
|
|
|
|
- // must return E_FAIL to allow it to be passed on to the other
|
|
|
|
|
- // context menu handlers that might implement that verb.
|
|
|
|
|
|
|
+ auto offset = LOWORD(pici->lpVerb);
|
|
|
|
|
+ if (offset < m_info.menuItems.size())
|
|
|
return E_FAIL;
|
|
return E_FAIL;
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ command = m_info.menuItems[offset].command;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ OCClientInterface::SendRequest(command.data(), m_selectedFiles);
|
|
|
return S_OK;
|
|
return S_OK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
|
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
|
|
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
|
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
|
|
{
|
|
{
|
|
|
- HRESULT hr = E_INVALIDARG;
|
|
|
|
|
-
|
|
|
|
|
- switch (idCommand) {
|
|
|
|
|
- case IDM_SHARE:
|
|
|
|
|
- if (uFlags == GCS_VERBW) {
|
|
|
|
|
- // GCS_VERBW is an optional feature that enables a caller to
|
|
|
|
|
- // discover the canonical name for the verb passed in through
|
|
|
|
|
- // idCommand.
|
|
|
|
|
- hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
|
|
|
|
- L"OCShareViaOC");
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case IDM_COPYLINK:
|
|
|
|
|
- if (uFlags == GCS_VERBW) {
|
|
|
|
|
- hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
|
|
|
|
- L"OCCopyLink");
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case IDM_EMAILLINK:
|
|
|
|
|
- if (uFlags == GCS_VERBW) {
|
|
|
|
|
- hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
|
|
|
|
- L"OCEmailLink");
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ if (idCommand < m_info.menuItems.size() && uFlags == GCS_VERBW) {
|
|
|
|
|
+ return StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax,
|
|
|
|
|
+ m_info.menuItems[idCommand].command.data());
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // If the idCommand or uFlags is not supported by this context menu
|
|
|
|
|
- // extension handler, return E_INVALIDARG.
|
|
|
|
|
-
|
|
|
|
|
- return hr;
|
|
|
|
|
|
|
+ return E_INVALIDARG;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#pragma endregion
|
|
|
|
|
|
|
+#pragma endregion
|