mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-24 05:55:59 +03:00
0af97156c9
Timeouts don't work with named pipe, so wait for 50ms to let time for the client to answer
267 lines
No EOL
6.5 KiB
C++
267 lines
No EOL
6.5 KiB
C++
/**
|
|
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Lesser General Public License as published by the Free
|
|
* Software Foundation; either version 2.1 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "OCContextMenu.h"
|
|
#include "OCClientInterface.h"
|
|
|
|
#include <shobjidl.h>
|
|
#include <shlwapi.h>
|
|
#include <shellapi.h>
|
|
#include <StringUtil.h>
|
|
|
|
extern HINSTANCE g_hInst;
|
|
extern long g_cDllRef;
|
|
|
|
#define IDM_SHARE 0
|
|
|
|
|
|
|
|
OCContextMenu::OCContextMenu(void)
|
|
: m_cRef(1)
|
|
, m_pszMenuText(L"&Share")
|
|
, m_pszVerb("ocshare")
|
|
, m_pwszVerb(L"ocshare")
|
|
, m_pszVerbCanonicalName("OCShareViaOC")
|
|
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
|
, m_pszVerbHelpText("Share via ownCloud")
|
|
, m_pwszVerbHelpText(L"Share via ownCloud")
|
|
{
|
|
InterlockedIncrement(&g_cDllRef);
|
|
}
|
|
|
|
OCContextMenu::~OCContextMenu(void)
|
|
{
|
|
InterlockedDecrement(&g_cDllRef);
|
|
}
|
|
|
|
|
|
void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
|
{
|
|
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
|
}
|
|
|
|
|
|
#pragma region IUnknown
|
|
|
|
// Query to the interface the component supported.
|
|
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(OCContextMenu, IContextMenu),
|
|
QITABENT(OCContextMenu, IShellExtInit),
|
|
{ 0 },
|
|
};
|
|
return QISearch(this, qit, riid, ppv);
|
|
}
|
|
|
|
// Increase the reference count for an interface on an object.
|
|
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// Decrease the reference count for an interface on an object.
|
|
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
|
{
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef) {
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
#pragma endregion
|
|
|
|
|
|
#pragma region IShellExtInit
|
|
|
|
// Initialize the context menu handler.
|
|
IFACEMETHODIMP OCContextMenu::Initialize(
|
|
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
|
{
|
|
if (!pDataObj) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM stm;
|
|
|
|
if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) {
|
|
// Get an HDROP handle.
|
|
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
|
if (hDrop) {
|
|
// Ignore multi-selections
|
|
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
|
if (nFiles == 1) {
|
|
// Get the path of the file.
|
|
if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock(stm.hGlobal);
|
|
}
|
|
|
|
ReleaseStgMedium(&stm);
|
|
}
|
|
|
|
// If any value other than S_OK is returned from the method, the context
|
|
// menu item is not displayed.
|
|
return hr;
|
|
}
|
|
|
|
#pragma endregion
|
|
|
|
|
|
#pragma region IContextMenu
|
|
|
|
void InsertSeperator(HMENU hMenu, UINT indexMenu)
|
|
{
|
|
// Add a separator.
|
|
MENUITEMINFO sep = { sizeof(sep) };
|
|
sep.fMask = MIIM_TYPE;
|
|
sep.fType = MFT_SEPARATOR;
|
|
InsertMenuItem(hMenu, indexMenu, TRUE, &sep);
|
|
}
|
|
|
|
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
|
{
|
|
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
|
|
if (CMF_DEFAULTONLY & uFlags)
|
|
{
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
}
|
|
|
|
bool skip = true;
|
|
for (const std::wstring path : OCClientInterface::WatchedDirectories()) {
|
|
if (StringUtil::begins_with(std::wstring(m_szSelectedFile), path)) {
|
|
skip = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (skip) {
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
|
}
|
|
|
|
InsertSeperator(hMenu, indexMenu);
|
|
indexMenu++;
|
|
|
|
MENUITEMINFO mii = { sizeof(mii) };
|
|
mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
|
mii.wID = idCmdFirst + IDM_SHARE;
|
|
mii.fType = MFT_STRING;
|
|
mii.dwTypeData = m_pszMenuText;
|
|
mii.fState = MFS_ENABLED;
|
|
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
indexMenu++;
|
|
InsertSeperator(hMenu, indexMenu);
|
|
|
|
|
|
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
|
// Set the code value to the offset of the largest command identifier
|
|
// that was assigned, plus one (1).
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
|
}
|
|
|
|
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|
{
|
|
|
|
// For the Unicode case, if the high-order word is not zero, the
|
|
// command's verb string is in lpcmi->lpVerbW.
|
|
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
|
{
|
|
// Is the verb supported by this context menu extension?
|
|
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
|
{
|
|
OnVerbDisplayFileName(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;
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
OnVerbDisplayFileName(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;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
|
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (idCommand == IDM_SHARE)
|
|
{
|
|
switch (uFlags)
|
|
{
|
|
case GCS_HELPTEXTW:
|
|
// Only useful for pre-Vista versions of Windows that have a
|
|
// Status bar.
|
|
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
|
m_pwszVerbHelpText);
|
|
break;
|
|
|
|
case 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,
|
|
m_pwszVerbCanonicalName);
|
|
break;
|
|
|
|
default:
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
// If the command (idCommand) is not supported by this context menu
|
|
// extension handler, return E_INVALIDARG.
|
|
|
|
return hr;
|
|
}
|
|
|
|
#pragma endregion |