2025-11-28 00:35:46 +09:00

150 lines
5.1 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
// ExplorerCommandState handlers are not a verb implementation method, it is a way to give a dynamic
// behavior to a static verb implementation, that is show or not. This handler is run on a background thread
// to avoid UI hangs. So, for example you can combine it with ExecuteCommand, DropTarget or CreateProcess
// verb to give them dynamic behavior. Only use this method if you cannot express your dynamic behavior
// using an AQS expression. There is a limitation to this in that this cannot be used on the default verb.
#include "Dll.h"
class CExplorerCommandStateHandler
: public IExplorerCommandState, public IInitializeCommand
{
public:
// IUnknown
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CExplorerCommandStateHandler, IExplorerCommandState), // required
QITABENT(CExplorerCommandStateHandler, IInitializeCommand), // optional
// QITABENT(CExplorerCommandStateHandler, IObjectWithSite), // optional. the site can be used to get the explorer browser or view. not implemented in this sample
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
{
delete this;
}
return cRef;
}
// IExplorerCommandState
// compute the visibility of the verb here, respect "fOkToBeSlow" if this is slow
// when called with fOkToBeSlow == FALSE return E_PENDING and this object will be called
// back on a background thread with fOkToBeSlow == TRUE
IFACEMETHODIMP GetState(IShellItemArray * /* psiItemArray */, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState)
{
HRESULT hr;
if (fOkToBeSlow)
{
Sleep(4 * 1000); // simulate expensive work
*pCmdState = ECS_ENABLED;
hr = S_OK;
}
else
{
*pCmdState = ECS_DISABLED;
// returning E_PENDING requests that a new instance of this object be called back
// on a background thread so that it can do work that might be slow
hr = E_PENDING;
}
return hr;
}
// IInitializeCommand
IFACEMETHODIMP Initialize(PCWSTR pszCommandName, IPropertyBag *ppb)
{
SetInterface(&_pPropBag, ppb);
return SHStrDup(pszCommandName, &_pszCommandName);
}
CExplorerCommandStateHandler() : _cRef(1), _pPropBag(NULL), _pszCommandName(NULL)
{
DllAddRef();
}
private:
virtual ~CExplorerCommandStateHandler()
{
SafeRelease(&_pPropBag);
CoTaskMemFree(_pszCommandName);
DllRelease();
}
long _cRef;
IPropertyBag *_pPropBag;
PWSTR _pszCommandName;
};
HRESULT CExplorerCommandStateHandler_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CExplorerCommandStateHandler *pVerbState = new (std::nothrow) CExplorerCommandStateHandler();
HRESULT hr = pVerbState ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
pVerbState->QueryInterface(riid, ppv);
pVerbState->Release();
}
return hr;
}
static WCHAR const c_szVerbDisplayName[] = L"CommandState Handler Verb";
static WCHAR const c_szVerbName[] = L"Sample.ExplorerCommandStateHandlerVerb";
static WCHAR const c_szProgID[] = L"txtfile";
HRESULT CExplorerCommandStateHandler_RegisterUnRegister(bool fRegister)
{
HRESULT hr;
if (fRegister)
{
// register a create process based verb. this could also be a delegate execute
// or drop target verb
CRegisterExtension registerCreateProcess(CLSID_NULL);
hr = registerCreateProcess.RegisterCreateProcessVerb(c_szProgID, c_szVerbName, L"notepad.exe %1", c_szVerbDisplayName);
if (SUCCEEDED(hr))
{
hr = registerCreateProcess.RegisterVerbAttribute(c_szProgID, c_szVerbName, L"NeverDefault");
if (SUCCEEDED(hr))
{
// now register the command state handler, this computes if this verb is enabled or not
CRegisterExtension re(__uuidof(CExplorerCommandStateHandler));
hr = re.RegisterInProcServer(c_szVerbDisplayName, L"Apartment");
if (SUCCEEDED(hr))
{
hr = re.RegisterExplorerCommandStateHandler(c_szProgID, c_szVerbName);
}
}
}
}
else
{
// best effort
CRegisterExtension registerCreateProcess(CLSID_NULL);
hr = registerCreateProcess.UnRegisterVerb(c_szProgID, c_szVerbName);
CRegisterExtension re(__uuidof(CExplorerCommandStateHandler));
hr = re.UnRegisterObject();
}
return hr;
}