VC6插件开发应用实例

一、背景

Eclipse中,对于JAVA项目,可在项目或者文件上的右键菜单Show in ->System Explorer中,直接在资源管理器中显示当前项目或当前文件所在文件夹,以便于在Windows资源管理器中对文件的操作管理。同样的,在Visual Studio 2010、2013、2015、2017等版本也有类似功能,VC6为早期版本,并无相应功能。本文通过对VC6 IDE插件的开发,实现了在VC6环境中直接打开资源管理器至当前项目所在文件夹,也可以打开命令行窗口,且路径直接切换至当前工作目录。先看效果:

VC6插件开发应用实例_第1张图片

二、实现过程

1、VC6中新建“DevStudio Add-in Wizard”插件工程。工程名为“OpenInExplorer”,插件项目向导中均使用默认选项,点击完成。向导完成后,生成的项目代码实际上为一COM组件。

VC6插件开发应用实例_第2张图片

VC6插件开发应用实例_第3张图片


2、生成项目中各类简要介绍(略),详见Microsoft参考文档

VC6插件开发应用实例_第4张图片

各个文件和类的解释参考微软Understanding the Results of the Add-in Wizard

3、在ResourceView视图中修改Bitmap资源:IDR_TOOLBAR_LARGE和IDR_TOOLBAR_MEDIUM文件。


4、在ResourceView视图中修改字串表,如下表所示:

ID

标题
IDS_CMD_STRING   \n在Windows资源管理器中打开-1\n在Windows资源浏览器中打开工程-2\n在Windows资源管理器中打开
IDS_CMD_STRING2   \n使用记事本打开1\n使用记事本打开2 \n使用记事本打开
IDS_CMD_STRING3   \n打开命令窗口1\n打开CMD窗口2\n打开命令窗口

5、在CDSAddin类的OnConnection函数中添加自己的工具栏按钮及要执行的命令,完整函数如下所示:

STDMETHODIMP CDSAddIn::OnConnection(IApplication* pApp, VARIANT_BOOL bFirstTime,
		long dwCookie, VARIANT_BOOL* OnConnection)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	// Store info passed to us
	IApplication* pApplication = NULL;
	if (FAILED(pApp->QueryInterface(IID_IApplication, (void**) &pApplication))
		|| pApplication == NULL)
	{
		*OnConnection = VARIANT_FALSE;
		return S_OK;
	}

	m_dwCookie = dwCookie;

	// Create command dispatch, send info back to DevStudio
	CCommandsObj::CreateInstance(&m_pCommands);
	m_pCommands->AddRef();

	// The QueryInterface above AddRef'd the Application object.  It will
	//  be Release'd in CCommand's destructor.
	m_pCommands->SetApplicationObject(pApplication);

	// (see stdafx.h for the definition of VERIFY_OK)

	VERIFY_OK(pApplication->SetAddInInfo((long) AfxGetInstanceHandle(),
		(LPDISPATCH) m_pCommands, IDR_TOOLBAR_MEDIUM, IDR_TOOLBAR_LARGE, m_dwCookie));

	// Inform DevStudio of the commands we implement

	// TODO: Replace the AddCommand call below with a series of calls,
	//  one for each command your add-in will add.

	// The command name should not be localized to other languages.  The 
	//  tooltip, command description, and other strings related to this
	//  command are stored in the string table (IDS_CMD_STRING) and should
	//  be localized.
	LPCTSTR szCommand = _T("OpenInExplorerCommand");
	VARIANT_BOOL bRet;
	CString strCmdString;
	strCmdString.LoadString(IDS_CMD_STRING);
	strCmdString = szCommand + strCmdString;
	CComBSTR bszCmdString(strCmdString);
	CComBSTR bszMethod(_T("OpenInExplorerCommandMethod"));
	CComBSTR bszCmdName(szCommand);
	VERIFY_OK(pApplication->AddCommand(bszCmdString, bszMethod, 0, m_dwCookie, &bRet));
	if (bRet == VARIANT_FALSE)
	{
		// AddCommand failed because a command with this name already
		//  exists.  You may try adding your command under a different name.
		//  Or, you can fail to load as we will do here.
		*OnConnection = VARIANT_FALSE;
		return S_OK;
	}

	// Add toolbar buttons only if this is the first time the add-in
	//  is being loaded.  Toolbar buttons are automatically remembered
	//  by Developer Studio from session to session, so we should only
	//  add the toolbar buttons once.
	if (bFirstTime == VARIANT_TRUE)
	{
		VERIFY_OK(pApplication->
			AddCommandBarButton(dsGlyph, bszCmdName, m_dwCookie));
	}
	
	/******添加自定义工具栏按钮 Start************************************************************/
	// 添加第二个工具栏按钮
	LPCTSTR szOpenNotepadCommand = _T("OpenInNotepad");

	CString strOpenNotepadCmdString;
	strOpenNotepadCmdString.LoadString(IDS_CMD_STRING2);
	strOpenNotepadCmdString = szOpenNotepadCommand + strOpenNotepadCmdString;

	CComBSTR bszOpenNotepadCmdString(strOpenNotepadCmdString);
	CComBSTR bszOpenNotepadMethod(_T("OpenInNotepad"));
	CComBSTR bszOpenNotepadCmdName(szOpenNotepadCommand);

	VERIFY_OK(pApplication->AddCommand(bszOpenNotepadCmdString, bszOpenNotepadMethod, 1, m_dwCookie, &bRet));
	if (bRet == VARIANT_FALSE)
	{
		*OnConnection = VARIANT_FALSE;
		return S_OK;
	}
	if (bFirstTime == VARIANT_TRUE)
	{
		VERIFY_OK(pApplication->AddCommandBarButton(dsGlyph, bszOpenNotepadCmdName, m_dwCookie));
	}

	// 添加第三个工具栏按钮
	LPCTSTR szConsoleCommand = _T("OpenInCommand");
	CComBSTR bszConsoleCmdName(szConsoleCommand);

	CString strConsoleCmdString;
	strConsoleCmdString.LoadString(IDS_CMD_STRING3);
	strConsoleCmdString = szConsoleCommand + strConsoleCmdString;
	CComBSTR bszConsoleCmdString(strConsoleCmdString);

	CComBSTR bszConsoleMethod(_T("OpenInCommand"));

	VERIFY_OK(pApplication->AddCommand(bszConsoleCmdString, bszConsoleMethod, 4, m_dwCookie, &bRet));
	if (bRet == VARIANT_FALSE)
	{
		*OnConnection = VARIANT_FALSE;
		return S_OK;
	}
	if (bFirstTime == VARIANT_TRUE)
	{
		VERIFY_OK(pApplication->AddCommandBarButton(dsGlyph, bszConsoleCmdName, m_dwCookie));
	}
		
	/**********添加自定义工具栏按钮 End*************************************************************/
	*OnConnection = VARIANT_TRUE;
	return S_OK;
}


6、ClassView视图中,在CCommands类的接口上添加方法OpenInNotepad()和OpenInCommand()。并分别在CCommands类中实现这些方法。具体代码如下:

STDMETHODIMP CCommands::OpenInExplorerCommandMethod() 
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Replace this with the actual code to execute this command
	//  Use m_pApplication to access the Developer Studio Application object,
	//  and VERIFY_OK to see error strings in DEBUG builds of your add-in
	//  (see stdafx.h)

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	
	//获得DevStudio当前工作目录
	BSTR bstrCurrentDirectory;
	m_pApplication->get_CurrentDirectory(&bstrCurrentDirectory);
	char* lpszDir = _com_util::ConvertBSTRToString(bstrCurrentDirectory);

        // operation params:"open", "runas", "print", "edit", "explorer", "find"
       ::ShellExecute(NULL,"open",lpszDir,NULL,lpszDir,SW_SHOWNORMAL);
	
	//释放资源
	::SysFreeString(bstrCurrentDirectory);
	delete[] lpszDir;

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
}

以上使用了com工具,故需要引入相应头文件和依赖库文件。

//_com_util::ConvertBSTRToString()函数将要用到的头文件和库依赖文件
#include "comutil.h"
#pragma comment(lib, "comsupp.lib")

OpenInNotepad()

STDMETHODIMP CCommands::OpenInNotepad()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

	
	CHAR path[MAX_PATH] = {NULL};
	::GetSystemDirectory(path,MAX_PATH);
	HINSTANCE hinst = NULL;
	// hinst = ::ShellExecute(NULL, NULL, "notepad.exe", NULL, path, SW_SHOWNORMAL);
	// hinst = ::ShellExecute(NULL,"open","C:\\Windows\\System32\\notepad.exe",NULL,NULL,SW_SHOWNORMAL);

	UINT ret = ::WinExec("notepad.exe", SW_SHOWNORMAL);
	
	if( SE_ERR_NOASSOC == (int)hinst){
		::MessageBox(NULL, "Call notepad.exe Exception!", "OpenInNotepad", MB_OK | MB_ICONWARNING);
	}
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

	return S_OK;
}


OpenInCommand()

STDMETHODIMP CCommands::OpenInCommand()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	HINSTANCE hinst = NULL;

	// 执行外部命令的几个函数:WinExec(), ShellExecute(), system(), CreateProcess()

	// 打开IDE当前项目路径
	hinst = ::ShellExecute(NULL,"open","c:\\windows\\system32\\cmd.exe",NULL,NULL,SW_SHOWNORMAL);
	
	// 打开IDE当前项目路径
	// hinst = ::ShellExecute(NULL,"open","cmd.exe",NULL,NULL,SW_SHOWNORMAL);

	// 打开C:\Windows\System32目录
	// hinst = ::ShellExecute(NULL, NULL, "cmd.exe", NULL, "C:\\Windows\\System32\\", SW_SHOWNORMAL);

	
	//::WinExec("cmd.exe", SW_SHOWNORMAL);
	// system("c:\\windows\\system32\\cmd.exe");
	// system("notepad.exe");

	// 使用浏览器打开网页
	// hinst = ::ShellExecute(NULL,"open","http://localhost",NULL,NULL,SW_SHOWNORMAL);

	// 使用邮件工具编辑邮件
	// hinst = ::ShellExecute(NULL,"open","mailto:[email protected]?subject=Hello&Body=this is a test",NULL,NULL,SW_SHOWNORMAL);

	if( SE_ERR_NOASSOC == (int)hinst){
		::MessageBox(NULL, "Call cmd.exe Exception!", "OpenInNotepad", MB_OK | MB_ICONWARNING);
	}

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

	return S_OK;
}


7、编译链接完成后实现自动注册组件。VC6IDE中->菜单“工程”->设置->Post-Build步骤,新增命令,命令行如下

regsvr32.exe $(OutDir)\OpenInExplorer.dll /s

/s参数表示 无声,不显示注册成功与否的消息框。


VC6插件开发应用实例_第5张图片

7、编译、注册组件后,VC6IDE中->菜单“工具”->定制->附加项和宏文件,点击该界面的“浏览”按钮,选中本项目的OpenInExplorer.dll文件。选中插件“OpenInExplorer Developer Studio Add-in”。关闭后弹出工具栏对话框。具体也可参考CmdWnd: Issue IDE Command in a Command Window

然后IDE可增加带3个命令按钮的工具栏对话框。在任意打开的项目中点击自定义的工具栏按钮,发现已经实现目标。直接点击按钮1,可在打开的资源管理器中直接浏览本项目文件或对项目文件进行IDE之外的操作。

三、参考文档

Visual C++ Developer Studio Add-in Samples

Overview: Add-ins for the Visual C++ Developer Studio

How to: Create Add-in

微软实现步骤示例Creating Add-ins Using Visual C++

四、注意事项

如果在windows 7以上编译,请使用管理员权限打开vc6,否则因权限不足,会导致组件注册失败。

五、完整源代码下载:OpenInExplorer

你可能感兴趣的:(VC,IDE插件)