class CContextMenu : public IContextMenu, public IShellExtInit
{
public:
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IContextMenu
STDMETHODIMP QueryContextMenu(
HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
STDMETHODIMP GetCommandString(
UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
// IShellExtInit
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
CContextMenu();
~CContextMenu();
private:
LONG m_cRef;
};
class CClassFactory : public IClassFactory
{
public:
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IClassFactory
STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
STDMETHODIMP LockServer(BOOL fLock);
};
#pragma comment(lib, "shlwapi.lib")
#include <ShlObj.h>
#include <Shlwapi.h>
#include <Windows.h>
#include "aaa.h"
// 関数プロトタイプ宣言
void LockModule(BOOL bLock);
BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData);
void Trace(LPCTSTR ptcFormat, ...);
// グローバル変数
const CLSID CLSID_ContextMenuSample = {0x6986c66a, 0x401f, 0x4535,
{0x89, 0x18, 0x48, 0x07, 0x29, 0x39, 0xd2, 0xa4}};
const TCHAR g_szClsid[] = TEXT("{6986C66A-401F-4535-8918-48072939D2A4}");
const TCHAR g_szProgid[] = TEXT("Sample.ShellExtension");
const TCHAR g_szExt[] = TEXT(".aaa");
const TCHAR g_szHandlerName[] = TEXT("My ShortcutMenu Handler");
LONG g_lLocks = 0;
HINSTANCE g_hinstDll = NULL;
//==============================================================================
// CContextMenu
CContextMenu::CContextMenu()
{
m_cRef = 1;
LockModule(TRUE);
}
CContextMenu::~CContextMenu()
{
LockModule(FALSE);
}
STDMETHODIMP CContextMenu::QueryInterface(REFIID riid, void **ppvObject)
{
*ppvObject = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IContextMenu)) {
*ppvObject = static_cast<IContextMenu *>(this);
} else if (IsEqualIID(riid, IID_IPersist) || IsEqualIID(riid, IID_IShellExtInit)) {
*ppvObject = static_cast<IShellExtInit *>(this);
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CContextMenu::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CContextMenu::Release()
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
//------------------------------------------------------------------------------
// IContextMenu
STDMETHODIMP CContextMenu::QueryContextMenu(
HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
MENUITEMINFO mii;
if (uFlags & CMF_DEFAULTONLY) {
return MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
mii.cbSize = sizeof (MENUITEMINFO);
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.wID = idCmdFirst;
mii.dwTypeData = TEXT("A");
InsertMenuItem(hmenu, indexMenu, TRUE, &mii);
return MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}
STDMETHODIMP CContextMenu::GetCommandString(
UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
switch (idCmd) {
case 0:
switch (uFlags) {
case GCS_HELPTEXTA:
lstrcpyA(pszName, "説明文A");
break;
case GCS_HELPTEXTW:
lstrcpyW((LPWSTR)pszName, L"説明文A");
break;
case GCS_VERBA:
lstrcpyA(pszName, "A");
break;
case GCS_VERBW:
lstrcpyW((LPWSTR)pszName, L"A");
break;
}
break;
default:
return E_FAIL;
}
return S_OK;
}
STDMETHODIMP CContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
UINT idCmd = LOWORD(pici->lpVerb);
if (HIWORD(pici->lpVerb) != 0) {
return E_INVALIDARG;
}
switch (idCmd) {
case 0:
MessageBox(NULL, TEXT("A"), TEXT("OK"), MB_OK);
break;
}
return S_OK;
}
//------------------------------------------------------------------------------
// IShellExtInit
STDMETHODIMP CContextMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
{
Trace(L"Initialize\n");
// Trace(L"%u\n", pidlFolder->mkid.cb);
return S_OK;
}
//==============================================================================
// CClassFactory
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObject)
{
*ppvObject = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) {
*ppvObject = static_cast<IClassFactory *>(this);
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
{
LockModule(TRUE);
return 2;
}
STDMETHODIMP_(ULONG) CClassFactory::Release()
{
LockModule(FALSE);
return 1;
}
//------------------------------------------------------------------------------
// IClassFactory
STDMETHODIMP CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
CContextMenu *p;
HRESULT hr;
*ppvObject = NULL;
if (pUnkOuter != NULL) {
return CLASS_E_NOAGGREGATION;
}
p = new CContextMenu();
if (p == NULL) {
return E_OUTOFMEMORY;
}
hr = p->QueryInterface(riid, ppvObject);
p->Release();
return hr;
}
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
LockModule(fLock);
return S_OK;
}
//==============================================================================
// DLL Export
STDAPI DllCanUnloadNow(void)
{
return (g_lLocks == 0) ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
static CClassFactory serverFactory;
HRESULT hr;
*ppv = NULL;
if (IsEqualCLSID(rclsid, CLSID_ContextMenuSample)) {
hr = serverFactory.QueryInterface(riid, ppv);
} else {
hr = CLASS_E_CLASSNOTAVAILABLE;
}
return hr;
}
STDAPI DllRegisterServer(void)
{
TCHAR szModulePath[MAX_PATH];
TCHAR szKey[256];
wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("ShellExtension Sample"))) {
return E_FAIL;
}
GetModuleFileName(g_hinstDll, szModulePath, _countof(szModulePath));
wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, szModulePath)) {
return E_FAIL;
}
wsprintf(szKey, TEXT("CLSID\\%s\\InprocServer32"), g_szClsid);
if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, TEXT("ThreadingModel"), TEXT("Apartment"))) {
return E_FAIL;
}
wsprintf(szKey, TEXT("%s"), g_szExt);
if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, (LPTSTR)g_szProgid)) {
return E_FAIL;
}
wsprintf(szKey, TEXT("%s\\shellex\\ContextMenuHandlers\\%s"), g_szProgid, g_szHandlerName);
if (!CreateRegistryKey(HKEY_CLASSES_ROOT, szKey, NULL, (LPTSTR)g_szClsid)) {
return E_FAIL;
}
return S_OK;
}
STDAPI DllUnregisterServer(void)
{
TCHAR szKey[256];
wsprintf(szKey, TEXT("CLSID\\%s"), g_szClsid);
SHDeleteKey(HKEY_CLASSES_ROOT, szKey);
SHDeleteKey(HKEY_CLASSES_ROOT, g_szExt);
SHDeleteKey(HKEY_CLASSES_ROOT, g_szProgid);
return S_OK;
}
BOOL APIENTRY DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
g_hinstDll = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
break;
}
return TRUE;
}
//==============================================================================
// Function
void LockModule(BOOL bLock)
{
if (bLock) {
InterlockedIncrement(&g_lLocks);
} else {
InterlockedDecrement(&g_lLocks);
}
}
BOOL CreateRegistryKey(HKEY hKeyRoot, LPTSTR lpszKey, LPTSTR lpszValue, LPTSTR lpszData)
{
HKEY hKey;
LONG lResult;
DWORD dwSize;
lResult = RegCreateKeyEx(hKeyRoot, lpszKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_WRITE, NULL, &hKey, NULL);
if (lResult != ERROR_SUCCESS) {
return FALSE;
}
if (lpszData != NULL) {
dwSize = (lstrlen(lpszData) + 1) * sizeof (TCHAR);
} else {
dwSize = 0;
}
RegSetValueEx(hKey, lpszValue, 0, REG_SZ, (LPBYTE)lpszData, dwSize);
RegCloseKey(hKey);
return TRUE;
}
void Trace(LPCTSTR ptcFormat, ...)
{
va_list args;
TCHAR atcBuf[512];
int iRet;
va_start(args, ptcFormat);
iRet = wsprintf(atcBuf, ptcFormat, args);
if (0 < iRet) {
OutputDebugString(atcBuf);
}
va_end(args);
}