開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 プロジェクト
プロジェクト名 aaa
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト

レジストリへの登録
regsvr32 C:\aaa.dll

レジストリの登録を解除
regsvr32 /u C:\aaa.dll

DLLの置き換え
  • レジストリの登録を解除
  • シェル(explorer)を再起動

デバッグにはDebugViewを使う。

参考
ショートカットメニュー ハンドラ

aaa.def
; リンカー/入力/モジュール定義ファイル
 
LIBRARY	"aaa"
 
EXPORTS
	DllCanUnloadNow PRIVATE
	DllGetClassObject PRIVATE
	DllRegisterServer PRIVATE
	DllUnregisterServer PRIVATE
 

aaa.h
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);
};
 

aaa.cpp
#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);
}
 
最終更新:2012年09月01日 16:44