首页 > 代码库 > VS之插件实现

VS之插件实现

程序开发中,我们不可能把所有的功能一次全部实现,那么我们就应该留一些接口出来,让其他的功能以插件的形式添加到我们的程序中,这样我们的程序不用做任何更改就可以添加很多新的功能了。我们常用的软件如excel、photoshop等,都有这些功能,那么该如何实现呢?本文通过一个简单的例子实现。

使用工具:VS2008

使用语言:C++

开发步骤:

1.插件应用程序

1.1新建对话框应用程序

技术分享

1.2新建基类

技术分享

1.3添加基类纯虚函数

PlugPeople.h
#pragma once

typedef bool (*LPFNREGISTER)(void**);

class CPlugPeople
{
public:
	CPlugPeople(void){};
	~CPlugPeople(void){};
	virtual void Show(void){};
};

1.4加载动态库并显示效果

界面上添加一个列表,用于显示动态库的路径名
	//属性设置
	m_list.ModifyStyle(LVS_TYPEMASK,LVS_REPORT & LVS_TYPEMASK | LVS_SINGLESEL);//important for show
	DWORD dwStyle = m_list.GetExtendedStyle();
	m_list.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

	m_list.InsertColumn(0,_T("PathName"),LVCFMT_LEFT,480,0);
添加一个按钮,用于选择文件夹,并枚举选中文件夹,将动态库路径名显示到列表中
void CPlugAppDemoDlg::OnBnClickedBtnLoad()
{
	// TODO: 在此添加控件通知处理程序代码
	char   szDir[MAX_PATH]; 
	BROWSEINFO   bi; 
	ITEMIDLIST   *pidl; 

	bi.hwndOwner   =   this->m_hWnd; 
	bi.pidlRoot   =   NULL; 
	bi.pszDisplayName   =   (LPWSTR)szDir; 
	bi.lpszTitle   =   _T("请选择目录 ");//strDlgTitle; 
	bi.ulFlags   =   BIF_RETURNONLYFSDIRS; 
	bi.lpfn   =   NULL; 
	bi.lParam   =   0; 
	bi.iImage   =   0; 

	pidl   =   SHBrowseForFolder(&bi); 
	if(pidl   ==   NULL)   
		return ; 
	if(!SHGetPathFromIDList(pidl, (LPWSTR)szDir))   
		return ; 
	CString sTargetFullPath = _T("");
	sTargetFullPath.Format(_T("%s"),szDir);

	if(sTargetFullPath.IsEmpty())
	{
		return;
	}

	m_list.DeleteAllItems();
	int index = 0;

	CString strPath = sTargetFullPath;
	CString strFullName = _T("");

	WIN32_FIND_DATA FindFileData;   
    BOOL bFinishFind = FALSE;   
    ZeroMemory(&FindFileData, sizeof(WIN32_FIND_DATA));    
    strPath += _T("\\*.*");   
       
    HANDLE hFindFile = FindFirstFile(strPath, &FindFileData);   
    if (hFindFile == INVALID_HANDLE_VALUE)  //枚举失败   
    {   
        return ;   
    }   
    while(hFindFile != INVALID_HANDLE_VALUE && GetLastError() !=ERROR_NO_MORE_FILES)   
    {   
        if ((_tcscmp( FindFileData.cFileName  , _T("."))) ==0  ||    
            (_tcscmp(FindFileData.cFileName , _T("..")) == 0))     
        {   
            FindNextFile(hFindFile , &FindFileData);   
            continue;   
        }   
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)       //递归枚举文件夹里面的   
        {   
			FindNextFile(hFindFile , &FindFileData); 
            SetLastError(0);   
            continue;   
        }
		
		strFullName = sTargetFullPath + _T("\\") + FindFileData.cFileName;
		CString strType = strFullName.Right(4);
		strType.MakeLower();
		if(_T(".dll") == strType)
		{
			m_list.InsertItem(index,strFullName);
			index++;
		}
	
        FindNextFile(hFindFile , &FindFileData);   
    }
}
点击了列表中哪个动态库则显示对应动态库信息
void CPlugAppDemoDlg::OnNMClickListDll(NMHDR *pNMHDR, LRESULT *pResult)
{
	//LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	int nItem = pNMListView->iItem;

	if(-1 == nItem)
	{
		return ;
	}
	else
	{
		RunDLL(m_list.GetItemText(nItem,0));
	}

	*pResult = 0;
}

void CPlugAppDemoDlg::RunDLL(CString strPathName)
{
	CPlugPeople* pPlug = NULL;
	HINSTANCE hIn = NULL;
	hIn = LoadLibrary(strPathName);

	if(hIn != INVALID_HANDLE_VALUE)
	{}
	else
	{
		MessageBox(_T("Load DLL error"));
		return;
	}

	LPFNREGISTER lpfnRegister = NULL;
	
	char p[256] = {0};
	CString str = _T("CreateObject");
	int cnt = str.GetLength();
	for(int i=0; i<cnt; i++)
	{
		p[i] = str.GetAt(i);
	}
	lpfnRegister = (LPFNREGISTER)GetProcAddress(hIn,p);

	bool result = false;
	if(lpfnRegister)
	{
		result = (*lpfnRegister)((void**)&pPlug);
	}
	else
	{
		FreeLibrary(hIn);
		return;
	}

	if(result)
	{}
	else
	{
		MessageBox(_T("Create Object error"));
		FreeLibrary(hIn);
		return;
	}

	pPlug->Show();

	delete pPlug;
	pPlug = NULL;
	FreeLibrary(hIn);
}

2.插件动态库

2.1新建动态库

技术分享

2.2添加基类文件

技术分享

2.3从基类派生自己的类

PlugChild.h
#pragma once
#include "plugpeople.h"

class CPlugChild :
	public CPlugPeople
{
public:
	CPlugChild(void);
	~CPlugChild(void);
	void Show(void);
};

2.4重写虚函数

PlugChild.cpp
#include "StdAfx.h"
#include "PlugChild.h"

CPlugChild::CPlugChild(void)
{
}

CPlugChild::~CPlugChild(void)
{
}

void CPlugChild::Show(void)
{
	AfxMessageBox(_T("小家伙吃了些葡萄..."));
}

2.5添加统一动态库函数接口,传递自己的类

PlugDllChildDemo.cpp

extern "C"
__declspec(dllexport) bool CreateObject(void** pObj)
{
	*pObj = new CPlugChild;
	return true;
}

3.应用程序中调用插件

3.1应用程序运行
技术分享

3.2选择动态库文件夹

技术分享

3.3选择完成后效果

技术分享

3.4点击效果

技术分享 技术分享 技术分享


源码下载


VS之插件实现