这是一个用来添加Explorer文件右键菜单的小工具,支持插件,这样就能减少在COM上打转的时间,将时间真正放到功能的实现上。
如下图显示的菜单,其中打开cmd是用插件加入的。
系统提一个头文件和lib文件,按照这个实现这些即可在菜单中添加命令。
简单的接口定义文件
#pragma
once
#include < Windows.h >
#define MAX_DESCRIPTION_SIZE 256
// 一个菜单所需要的所有基本数据,这是系统会提供的一个接口,在需要相关数据的时候从这里获取
class IMenuObjectData
{
public :
enum FileType {
File = 0x1 ,
Directory = 0x2 ,
None = 0x0
};
virtual HWND GetHwnd() = 0 ; // 取得explorer窗口句柄
virtual UINT GetFileCount() = 0 ; // 取得在弹出菜单时选中的文件个数
virtual const TCHAR * GetFileName( int index) = 0 ; // 文件名及类型
virtual FileType GetFileType( int index) = 0 ;
virtual BOOL IsInExplorer() = 0 ; // 是否在Explorer右边窗口弹出(即非左边的数状目录)
};
// 这是插件需要实现的接口
class IMenuControl
{
public :
virtual ~ IMenuControl() = 0 {}
virtual void SetMenuObjectData(IMenuObjectData * ) = 0 ; // 一开始
virtual UINT GetMenuCount() = 0 ; // 告诉系统你将要几个命令菜单项(Explorer的右键菜单)
virtual UINT InitMenu(HMENU hMenu, UINT uIndex, UINT uID) = 0 ; // 初始化这个菜单
virtual UINT GetSubMenuCount() = 0 ; // 告诉系统你将要几个子菜单(扩展工具的子菜单)
virtual UINT InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID) = 0 ; // 返回增加了菜单之后的index
virtual BOOL Invoke(UINT uID) = 0 ; // 命令被调用
virtual BOOL GetCmdDescription(UINT uID, TCHAR * pszDesc) = 0 ; // 需要被显示命令的tip
};
// IMenuControl*
typedef IMenuControl * (__stdcall * fnGetMenuControl)( void ); // 从插件中取得IMenuControl接口的方法
typedef void (__stdcall * fnReleaseMenuControl)(IMenuControl * ); // 告诉插件释放这个接口
void RegisterMenuControl(fnGetMenuControl, fnReleaseMenuControl); // 插件将自己的这两个函数注册给系统
#include < Windows.h >
#define MAX_DESCRIPTION_SIZE 256
// 一个菜单所需要的所有基本数据,这是系统会提供的一个接口,在需要相关数据的时候从这里获取
class IMenuObjectData
{
public :
enum FileType {
File = 0x1 ,
Directory = 0x2 ,
None = 0x0
};
virtual HWND GetHwnd() = 0 ; // 取得explorer窗口句柄
virtual UINT GetFileCount() = 0 ; // 取得在弹出菜单时选中的文件个数
virtual const TCHAR * GetFileName( int index) = 0 ; // 文件名及类型
virtual FileType GetFileType( int index) = 0 ;
virtual BOOL IsInExplorer() = 0 ; // 是否在Explorer右边窗口弹出(即非左边的数状目录)
};
// 这是插件需要实现的接口
class IMenuControl
{
public :
virtual ~ IMenuControl() = 0 {}
virtual void SetMenuObjectData(IMenuObjectData * ) = 0 ; // 一开始
virtual UINT GetMenuCount() = 0 ; // 告诉系统你将要几个命令菜单项(Explorer的右键菜单)
virtual UINT InitMenu(HMENU hMenu, UINT uIndex, UINT uID) = 0 ; // 初始化这个菜单
virtual UINT GetSubMenuCount() = 0 ; // 告诉系统你将要几个子菜单(扩展工具的子菜单)
virtual UINT InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID) = 0 ; // 返回增加了菜单之后的index
virtual BOOL Invoke(UINT uID) = 0 ; // 命令被调用
virtual BOOL GetCmdDescription(UINT uID, TCHAR * pszDesc) = 0 ; // 需要被显示命令的tip
};
// IMenuControl*
typedef IMenuControl * (__stdcall * fnGetMenuControl)( void ); // 从插件中取得IMenuControl接口的方法
typedef void (__stdcall * fnReleaseMenuControl)(IMenuControl * ); // 告诉插件释放这个接口
void RegisterMenuControl(fnGetMenuControl, fnReleaseMenuControl); // 插件将自己的这两个函数注册给系统
注释中已经很详细的说明了使用方法,下面是打开cmd这个菜单的插件的实现样例。
//
CmdTools.cpp : Defines the entry point for the DLL application.
//
#include " stdafx.h "
#include " ../ExternTools/ExternToolsDef.h "
#include < string >
using namespace std;
class CMyMenuControl : public IMenuControl
{
public :
CMyMenuControl() : m_pMenuData( 0 ), m_uID( 0 ) {}
virtual void SetMenuObjectData(IMenuObjectData * pMenuData) { m_pMenuData = pMenuData; }
virtual UINT GetMenuCount() { return 0 ; }
virtual UINT InitMenu(HMENU hMenu, UINT uIndex, UINT uID) { return 0 ; }
virtual UINT GetSubMenuCount();
virtual UINT InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID);
virtual BOOL Invoke(UINT uID);
virtual BOOL GetCmdDescription(UINT uID, TCHAR * pszDesc);
private :
IMenuObjectData * m_pMenuData;
UINT m_uID;
};
IMenuControl * __stdcall GetMenuControl()
{
return new CMyMenuControl();
}
void __stdcall ReleaseMenuControl(IMenuControl * pControl)
{
delete pControl;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
RegisterMenuControl(GetMenuControl, ReleaseMenuControl);
}
return TRUE;
}
UINT CMyMenuControl::GetSubMenuCount()
{
return 1 ;
}
UINT CMyMenuControl::InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID)
{
m_uID = uID;
InsertMenu(hMenu, uIndex, MF_STRING | MF_BYPOSITION, uID, " 打开cmd(&C) " );
return uIndex + 1 ;
}
BOOL CMyMenuControl::Invoke(UINT uID)
{
if (uID == m_uID)
{
if (m_pMenuData)
{
std:: string str(m_pMenuData -> GetFileName( 0 ));
if (m_pMenuData -> IsInExplorer())
{
string ::size_type pos = str.find_last_of( ' / ' );
if (pos != string ::npos)
{
str = str.substr( 0 , pos);
if (str.size() < 3 ) str += " / " ;
}
}
STARTUPINFO si;
si.cb = sizeof (si);
GetStartupInfo( & si);
PROCESS_INFORMATION pi;
if (::CreateProcess( 0 , " cmd.exe " , 0 , 0 , FALSE, 0 , 0 , str.c_str(), & si, & pi))
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
}
}
return TRUE;
}
return FALSE;
}
BOOL CMyMenuControl::GetCmdDescription(UINT uID, TCHAR * pszDesc)
{
if (uID == m_uID)
{
static TCHAR szDesc[] = " 当前目录下打开命令提示符 " ;
memcpy(pszDesc, szDesc, sizeof (szDesc));
return TRUE;
}
return FALSE;
}
//
#include " stdafx.h "
#include " ../ExternTools/ExternToolsDef.h "
#include < string >
using namespace std;
class CMyMenuControl : public IMenuControl
{
public :
CMyMenuControl() : m_pMenuData( 0 ), m_uID( 0 ) {}
virtual void SetMenuObjectData(IMenuObjectData * pMenuData) { m_pMenuData = pMenuData; }
virtual UINT GetMenuCount() { return 0 ; }
virtual UINT InitMenu(HMENU hMenu, UINT uIndex, UINT uID) { return 0 ; }
virtual UINT GetSubMenuCount();
virtual UINT InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID);
virtual BOOL Invoke(UINT uID);
virtual BOOL GetCmdDescription(UINT uID, TCHAR * pszDesc);
private :
IMenuObjectData * m_pMenuData;
UINT m_uID;
};
IMenuControl * __stdcall GetMenuControl()
{
return new CMyMenuControl();
}
void __stdcall ReleaseMenuControl(IMenuControl * pControl)
{
delete pControl;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
RegisterMenuControl(GetMenuControl, ReleaseMenuControl);
}
return TRUE;
}
UINT CMyMenuControl::GetSubMenuCount()
{
return 1 ;
}
UINT CMyMenuControl::InitSubMenu(HMENU hMenu, UINT uIndex, UINT uID)
{
m_uID = uID;
InsertMenu(hMenu, uIndex, MF_STRING | MF_BYPOSITION, uID, " 打开cmd(&C) " );
return uIndex + 1 ;
}
BOOL CMyMenuControl::Invoke(UINT uID)
{
if (uID == m_uID)
{
if (m_pMenuData)
{
std:: string str(m_pMenuData -> GetFileName( 0 ));
if (m_pMenuData -> IsInExplorer())
{
string ::size_type pos = str.find_last_of( ' / ' );
if (pos != string ::npos)
{
str = str.substr( 0 , pos);
if (str.size() < 3 ) str += " / " ;
}
}
STARTUPINFO si;
si.cb = sizeof (si);
GetStartupInfo( & si);
PROCESS_INFORMATION pi;
if (::CreateProcess( 0 , " cmd.exe " , 0 , 0 , FALSE, 0 , 0 , str.c_str(), & si, & pi))
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
}
}
return TRUE;
}
return FALSE;
}
BOOL CMyMenuControl::GetCmdDescription(UINT uID, TCHAR * pszDesc)
{
if (uID == m_uID)
{
static TCHAR szDesc[] = " 当前目录下打开命令提示符 " ;
memcpy(pszDesc, szDesc, sizeof (szDesc));
return TRUE;
}
return FALSE;
}
将插件放在注册表中
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE/SOFTWARE/ExternTools/dlls]
"cmdtool"="E://Develop//CmdTools//Debug//CmdTools.dll"
这样就可以了。
不知道怎么上载源文件,有兴趣的可以Email给我,共同研究