Click here to Skip to main content
15,896,915 members
Articles / Desktop Programming / MFC

Plug-In framework using DLLs

Rate me:
Please Sign up or sign in to vote.
4.84/5 (39 votes)
25 Jun 200211 min read 311.4K   8.7K   226  
Explains how to develop applications that support plug-ins
// PlugInSelectDialog.cpp : implementation file
//

#include "stdafx.h"
#include "PlugSDI.h"
#include "PlugInSelectDialog.h"

#include "Mainfrm.h"

#include <io.h>

// CPlugInSelectDialog dialog

IMPLEMENT_DYNAMIC(CPlugInSelectDialog, CDialog)
CPlugInSelectDialog::CPlugInSelectDialog(CWnd* pParent /*=NULL*/)
	: CDialog(CPlugInSelectDialog::IDD, pParent)
	, m_pImageList(NULL)
	, m_pImageHdrSmall(NULL)
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::CPlugInSelectDialog() method\n");
#endif
}

CPlugInSelectDialog::~CPlugInSelectDialog()
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::~CPlugInSelectDialog() method\n");
#endif

	if( m_pImageList != NULL)
		delete m_pImageList;
	if( m_pImageHdrSmall != NULL)
		delete m_pImageHdrSmall;

	m_szListValidFilenames.RemoveAll();
	m_szPlugInName.RemoveAll();
}

void CPlugInSelectDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_PLUG_IN, m_PlugInList);
}


BEGIN_MESSAGE_MAP(CPlugInSelectDialog, CDialog)
	ON_BN_CLICKED(IDC_PLUG_IN_LOAD, OnBnClickedPlugInLoad)
END_MESSAGE_MAP()


// CPlugInSelectDialog message handlers

BOOL CPlugInSelectDialog::OnInitDialog()
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::OnInitDialog() method\n");
#endif

	CPlugSDIApp *pApp;

	CDialog::OnInitDialog();

	// Bring data from dialog
	UpdateData(TRUE);

	// TODO:  Add extra initialization here
	pApp = (CPlugSDIApp *) AfxGetApp();

	// create image list for header items
	m_pImageHdrSmall = new CImageList();
	ASSERT(m_pImageHdrSmall != NULL); // serious allocation failure checking
	m_pImageHdrSmall->Create(16, 16, ILC_MASK, 3, 3);
	m_pImageHdrSmall->Add(pApp->LoadIcon(IDI_HDRICON1));
	m_pImageHdrSmall->Add(pApp->LoadIcon(IDI_HDRICON2));
	m_pImageHdrSmall->Add(pApp->LoadIcon(IDI_HDRICON3));

	// fill in image lists
	m_pImageList = new CImageList();
	ASSERT(m_pImageList != NULL); // serious allocation failure checking
	m_pImageList->Create(16, 16, TRUE,  1, 1);
	m_pImageList->Add(pApp->LoadIcon(IDI_ICON_PLUG_IN));

	m_PlugInList.SetExtendedStyle(m_PlugInList.GetExtendedStyle()
		| LVS_EX_HEADERDRAGDROP
		| LVS_EX_GRIDLINES
		| 0x00004000 // LVS_EX_LABELTIP
		| LVS_EX_FULLROWSELECT
		| LVS_EX_FLATSB
		| LVS_EX_CHECKBOXES);

	FillPlugIns();

	m_PlugInList.SetFocus();
	if (m_PlugInList.GetItemCount() > 0)
        m_PlugInList.SetSelectionMark(0);
	else
	{
#ifdef DEBUG
		TRACE("ERROR: No Plug-Ins found in directory\n");
#endif
		AfxMessageBox("ERROR: No Plug-Ins found.\nPlease place *.PLX file in the program executable path\nand then try again!!!");
		m_PlugInList.EnableWindow(FALSE);
		((CButton *) GetDlgItem(IDC_PLUG_IN_LOAD))->EnableWindow(FALSE);
		((CButton *) GetDlgItem(IDOK))->SetFocus();
	}

	return FALSE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

// Used to fill the list control with available Plug Ins
void CPlugInSelectDialog::FillPlugIns(void)
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::FillPlugIns() method\n");
#endif

	CRect           rect;
	int             nActualItem = 0;
	LV_ITEM         lvitem;
	CString         strItem1= _T("S. No");
	CString         strItem2= _T("Plug-In Name");
	CString         strItem3= _T("Plug-In Path");
	CString         szSerialNo(""), szPlugInName(""), szPlugInPath("");
	LPTSTR          pStrTemp1 = NULL, pStrTemp2 = NULL, pStrTemp3 = NULL;
	CPlugSDIApp     *pApp = NULL;

	nActualItem = 0;
	pApp = (CPlugSDIApp *)AfxGetApp();

	int nNumDLLsFound = FindDLLs(pApp);

	m_PlugInList.SetImageList(m_pImageList, LVSIL_SMALL);

	// insert two columns (REPORT mode) and modify the new header items
	m_PlugInList.GetWindowRect(&rect);
	m_PlugInList.InsertColumn(0, strItem1, LVCFMT_LEFT, rect.Width() * 2/20, 0);
	m_PlugInList.InsertColumn(1, strItem2, LVCFMT_LEFT, rect.Width() * 4/20, 0);
	m_PlugInList.InsertColumn(2, strItem3, LVCFMT_LEFT, rect.Width() * 13/20, 1);

	ModifyHeaderItems();

	POSITION pos1 = m_szPlugInName.GetHeadPosition();
	POSITION pos2 = m_szListValidFilenames.GetHeadPosition();

	// insert the items and subitems into the list view.
	for (int nItem = 0; nItem < nNumDLLsFound; nItem++)
	{
		szPlugInName = m_szPlugInName.GetNext(pos1);
		szPlugInPath = m_szListValidFilenames.GetNext(pos2);
		szSerialNo.Format("%d", nItem);
		for (int nSubItem = 0; nSubItem < 3; nSubItem++)
		{
			lvitem.mask = LVIF_TEXT | (nSubItem == 0? LVIF_IMAGE : 0);
			lvitem.iItem = (nSubItem == 0)? nItem : nActualItem;
			lvitem.iSubItem = nSubItem;

			// calculate the main and sub-item strings for the current item
			pStrTemp1= szSerialNo.GetBuffer(szSerialNo.GetLength());
			pStrTemp2= szPlugInName.GetBuffer(szPlugInName.GetLength());
			pStrTemp3= szPlugInPath.GetBuffer(szPlugInPath.GetLength());
			switch(nSubItem)
			{
				case 0: lvitem.pszText = pStrTemp1;
					break;
				case 1: lvitem.pszText = pStrTemp2;
					break;
				case 2: lvitem.pszText = pStrTemp3;
					break;
			}
//			lvitem.pszText = nSubItem == 0? pStrTemp1 : pStrTemp2;

			lvitem.iImage = 0;
			if (nSubItem == 0)
				// insert new item
				nActualItem = m_PlugInList.InsertItem(&lvitem);
			else
				// modify existing item (the sub-item text)
				m_PlugInList.SetItem(&lvitem);
		}

		// Check whether this item (DLL) was loaded previously
		if (((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.Find(szPlugInPath) != NULL)
		{
			ListView_SetCheckState(m_PlugInList.m_hWnd, nActualItem, TRUE);
		}
	}

	m_szPlugInName.RemoveAll();
	m_szListValidFilenames.RemoveAll();
}

// Used to find all available DLLs and store them in a list
int CPlugInSelectDialog::FindDLLs(CPlugSDIApp *pApp)
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::FindDLLs() method\n");
#endif

	long				lFile = 0L;
	struct _finddata_t	sFILE;
	DLLManager			tmpDLL; // for checking of functions
	CString				szSearchPath = "";
	CString				szCommandLine ;
	int					nNumDlls = 0 ;

	szCommandLine = GetCommandLine(); // so we know where to look for DLL's
	szCommandLine = szCommandLine.Left(szCommandLine.Find("PlugSDI.exe")); // lose exe name
	szCommandLine = szCommandLine.Right(szCommandLine.GetLength() - 1); // lose leading "

	szSearchPath = szCommandLine + "*.PLX";
	lFile = (long) _findfirst(szSearchPath, &sFILE);

	if (lFile != -1L)
	{
		do
		{
			tmpDLL.SetToolBarPointer(((CMainFrame *)pApp->m_pMainWnd)->GetToolBarObject());
			tmpDLL.SetDLLFileName(szCommandLine + sFILE.name);
			CString szName("");
			if (tmpDLL.GetDLLName(&szName) == true)
			{
				m_szPlugInName.AddTail(szName);
//				m_szPlugInName.AddTail(sFILE.name);
				m_szListValidFilenames.AddTail(tmpDLL.m_szDLLFileName);
				// Increment number of DLLs
				nNumDlls++;
//				tmpDLL.FreeDLL(); // release it
			}
		} while (_findnext(lFile, &sFILE) == 0);
		_findclose(lFile);
	}

	return nNumDlls;
}

// Used to modify list control's header items
void CPlugInSelectDialog::ModifyHeaderItems(void)
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::ModifyHeaderItems() method\n");
#endif

	HD_ITEM curItem;

	// retrieve embedded header control
	CHeaderCtrl* pHdrCtrl= NULL;
	pHdrCtrl= m_PlugInList.GetHeaderCtrl();

	pHdrCtrl->SetImageList(m_pImageHdrSmall);

	// add bitmaps to each header item
	pHdrCtrl->GetItem(0, &curItem);
	curItem.mask= HDI_IMAGE | HDI_FORMAT;
	curItem.iImage= 0;
	curItem.fmt= HDF_LEFT | HDF_IMAGE | HDF_STRING;
	pHdrCtrl->SetItem(0, &curItem);

	pHdrCtrl->GetItem(1, &curItem);
	curItem.mask= HDI_IMAGE | HDI_FORMAT;
	curItem.iImage= 1;
	curItem.fmt= HDF_LEFT | HDF_IMAGE | HDF_STRING;
	pHdrCtrl->SetItem(1, &curItem);

	pHdrCtrl->GetItem(2, &curItem);
	curItem.mask= HDI_IMAGE | HDI_FORMAT;
	curItem.iImage= 2;
	curItem.fmt= HDF_LEFT | HDF_IMAGE | HDF_STRING;
	pHdrCtrl->SetItem(2, &curItem);
}

// Used to load all available DLLs
bool CPlugInSelectDialog::LoadDLLs(CPlugSDIApp *pApp, CStringList *szListSelectedDLLs)
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::LoadDLLs() method\n");
#endif

	// We now have a list of valid DLL's. Load all of them
	if (((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs > 0)
	{
		POSITION pos = szListSelectedDLLs->GetHeadPosition();
//		((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs = nNumDlls;
		((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs = new DLLManager[((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs];
		for (int nNumDlls = 0 ;	nNumDlls < ((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs ; nNumDlls++)
		{
			((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].SetToolBarPointer(((CMainFrame *)pApp->m_pMainWnd)->GetToolBarObject());
            if (((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].LoadDLL(szListSelectedDLLs->GetNext(pos)) != false)
			{
				// Call InitPLugIn() to initialize Plug-In and update toolbar
				if (((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].InitDLL() == false)
				{
					AfxMessageBox("ERROR: Could not initialize " + ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].m_szDLLFileName + "\nInvalid or corrupt Plug-In\nPlease re-install it!!!");
	#ifdef DEBUG
					TRACE("ERROR: Could not call InitDLL(\"InitPlugIn\") method for \n\t" + ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].m_szDLLFileName + "\n");
	#endif
					return false;
				}
			}
			else
			{
				AfxMessageBox("ERROR: Could not initialize " + ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].m_szDLLFileName + "\nInvalid or corrupt Plug-In\nPlease re-install it!!!");
#ifdef DEBUG
				TRACE("ERROR: Could not call LoadDLL(\"GetPlugInName\") method for \n\t" + ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs[nNumDlls].m_szDLLFileName + "\n");
#endif
				return false;
			}
		}
	}
	else
	{
#ifdef DEBUG
		TRACE("ERROR: No Plug-Ins currently selected\n");
#endif
		AfxMessageBox("ERROR: No Plug-Ins currently selected.\nSelect and then try again!!!");
		return false;
	}

	// Recalculate layout due to GUI changes
	((CMainFrame *)pApp->m_pMainWnd)->RecalcLayout();

	// Set flag to indicate that Plug-Ins are now loaded
	((CMainFrame *)pApp->m_pMainWnd)->m_bIsPlugInLoaded = TRUE;

	return true;
}

void CPlugInSelectDialog::OnBnClickedPlugInLoad()
{
#ifdef DEBUG
	TRACE("Called CPlugInSelectDialog::OnBnClickedPlugInLoad() method\n");
#endif

	// TODO: Add your control notification handler code here
	int nCount = m_PlugInList.GetItemCount();
	int nNumDLLsSelected = 0;

	if (nCount <= 0)
	{
#ifdef DEBUG
		TRACE("ERROR: No Plug-Ins found\n");
#endif
		AfxMessageBox("ERROR: No Plug-Ins found!!!");
		return;
	}

	CStringList szList;

	for (int i=0; i<m_PlugInList.GetItemCount(); i++)
	{
		if (ListView_GetCheckState(m_PlugInList.m_hWnd, i) != 0)
		{
#ifdef DEBUG
		TRACE1("Item %d selected\n", i);
#endif
			szList.AddTail(m_PlugInList.GetItemText(i, 2));
			++nNumDLLsSelected;
		}
	}

	if (nNumDLLsSelected == 0)
	{
#ifdef DEBUG
		TRACE("ERROR: No Plug-Ins currently selected\n");
#endif
		if (AfxMessageBox("ERROR: No Plug-Ins currently selected.\nDo you want to Un-Load previously loaded Plug-Ins?",MB_YESNO) == IDYES)
		{
			CPlugSDIApp *pApp = (CPlugSDIApp *) AfxGetApp();

			// If Previous number of DLLs > 0 then, Free/Un-Load all of them
			if (((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs > 0)
			{
				// free the previously loaded DLL's
				delete [] ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs;
				((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs = NULL;
				((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs = 0;
				((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.RemoveAll();

				// Recalculate layout due to GUI changes
				((CMainFrame *)pApp->m_pMainWnd)->RecalcLayout();
			}

			// Set the new number of DLLs selected
			((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs = 0;
		}
		return;
	}
	else
	{
		CPlugSDIApp *pApp = (CPlugSDIApp *) AfxGetApp();

#ifdef DEBUG
		POSITION pos = szList.GetHeadPosition();
		CString str;
		do
		{
			str = szList.GetNext(pos);
			TRACE("LIST ITEM: " + str + "\n");
		}while(pos != NULL);
#endif
		// If Previous number of DLLs > 0 then, Free/Un-Load all of them
		if (((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs > 0)
		{
			// free the previously loaded DLL's
			delete [] ((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs;
			((CMainFrame *)pApp->m_pMainWnd)->m_pLoadedDLLs = NULL;
			((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs = 0;

			// Recalculate layout due to GUI changes
			((CMainFrame *)pApp->m_pMainWnd)->RecalcLayout();
		}

		// Set the new number of DLLs selected
		((CMainFrame *)pApp->m_pMainWnd)->m_nNumberOfDLLs = nNumDLLsSelected;

		// Load new set of DLLs
		LoadDLLs(pApp, &szList);

		((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.RemoveAll();
		((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.AddTail(&szList);
		szList.RemoveAll();

#ifdef DEBUG
		pos = ((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.GetHeadPosition();
		do
		{
			str = ((CMainFrame *)pApp->m_pMainWnd)->m_szListDLLsCurrentlyLoaded.GetNext(pos);
			TRACE("*************** LIST ITEM PREV: " + str + "\n");
		}while(pos != NULL);
#endif
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
Living in New Delhi (India). Did my Engg (Comp. Science) in 2000, and since then working on and off with VC++. It's my passion, and would really love to learn it to the very detail. Presently working as a software engg in a Telecom based firm. I've got around 3yrs experience in NMS (network management systems). Well thats all about me for now. Feel free to contact me...

Comments and Discussions