Click here to Skip to main content
15,885,032 members
Articles / Programming Languages / C++

Plugin System – an alternative to GetProcAddress and interfaces

Rate me:
Please Sign up or sign in to vote.
4.85/5 (64 votes)
25 May 2007CPOL10 min read 167.3K   1.9K   207  
A powerful and extensible way of creating plugin-based applications
// Host.cpp - a plugin-based image viewer
// In this version the host manually binds to all plugins through their GetParser function
//
// Part of the Plugin System tutorial
//
///////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <Shlwapi.h>
#include <stdio.h>
#include "ImageParser.h"

// a prototype for the GetParser function
typedef IImageParser *(*TGetParser)( void );

// the currently displayed bitmap
static HBITMAP g_Bitmap=NULL;

// a global list with all parsers
const int MAX_PARSERS=100;
IImageParser *g_Parsers[MAX_PARSERS];
int g_NumParsers=0;

// Adds the parser to the g_Parsers list
void AddParser( IImageParser *parser )
{
	g_Parsers[g_NumParsers++]=parser;
}

// Loads all plugins in the same folder as the EXE
void LoadPlugins( void )
{
	char path[_MAX_PATH];
	GetModuleFileName(NULL,path,_MAX_PATH);
	*PathFindFileName(path)=0;
	char spec[_MAX_PATH];
	sprintf(spec,"%s*.imp",path);
	WIN32_FIND_DATA data;
	// find all DLLs
	HANDLE h=FindFirstFile(spec,&data);
	if (h!=INVALID_HANDLE_VALUE) {
		do {
			char fname[_MAX_PATH];
			sprintf(fname,"%s%s",path,data.cFileName);
			HMODULE hModule=LoadLibrary(fname);
			if (hModule) {
				// get the parser pointer and add it to the parsers list
				TGetParser getparser=(TGetParser)GetProcAddress(hModule,"GetParser");
				if (getparser)
					AddParser(getparser());
			}
		} while (FindNextFile(h,&data));
		FindClose(h);
	}
}

// Loads an image file
void LoadImage( const char *fname )
{
	// find the parser for that type and load the image
	char ext[_MAX_EXT];
	_splitpath(fname,NULL,NULL,NULL,ext);
	for (int i=0;i<g_NumParsers;i++)
		if (g_Parsers[i]->SupportsType(ext)) {
			g_Bitmap=g_Parsers[i]->ParseFile(fname);
			break;
		}
}

LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	if (uMsg==WM_DESTROY)
		PostQuitMessage(0);

	if (uMsg==WM_PAINT) {
		// paints the window
		// if a bitmap is loaded - draw the bitmap
		// otherwise draw a text prompt
		PAINTSTRUCT ps;
		HDC hdc=BeginPaint(hwnd,&ps);
		if (g_Bitmap) {
			HDC hsrc=CreateCompatibleDC(hdc);
			SelectObject(hsrc,g_Bitmap);
			BITMAP bmp;
			GetObject(g_Bitmap,sizeof(bmp),&bmp);
			BitBlt(hdc,0,0,bmp.bmWidth,bmp.bmHeight,hsrc,0,0,SRCCOPY);
			DeleteDC(hsrc);
		}
		else {
			SelectObject(hdc,GetStockObject(DEFAULT_GUI_FONT));
			SetBkMode(hdc,TRANSPARENT);
			SetTextColor(hdc,0xFFFFFF);
			const char *s="Drop an image file here";
			TextOut(hdc,0,0,s,strlen(s));
		}
		EndPaint(hwnd,&ps);
		return 0;
	}

	if (uMsg==WM_DROPFILES) {
		// destroy the previous image
		if (g_Bitmap) DeleteObject(g_Bitmap);
		g_Bitmap=NULL;

		// get the file name
		HDROP hDrop=(HDROP)wParam;
		char fname[_MAX_PATH];
		DragQueryFile(hDrop,0,fname,_MAX_PATH);
		DragFinish(hDrop);

		// load the image file
		LoadImage(fname);
		InvalidateRect(hwnd,NULL,TRUE);
		return 0;
	}

	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	// Create main window
	WNDCLASS wc;
	memset(&wc,0,sizeof(wc));
	wc.style=CS_VREDRAW|CS_HREDRAW;
	wc.lpfnWndProc=WindowProc;
	wc.hInstance=hInstance;
	wc.hCursor=LoadCursor(NULL,IDC_CROSS);
	wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszClassName="ImageViewer";
	RegisterClass(&wc);
	HWND main=CreateWindowEx(WS_EX_APPWINDOW,"ImageViewer","ImageViewer",WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_CLIPCHILDREN,
		CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
	DragAcceptFiles(main,TRUE);
	LoadPlugins();

	// Process messages
	while (1) {
		MSG msg;
		if (!GetMessage(&msg,0,0,0)) break;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Ivo started programming in 1985 on an Apple ][ clone. He graduated from Sofia University, Bulgaria with a MSCS degree. Ivo has been working as a professional programmer for over 12 years, and as a professional game programmer for over 10. He is currently employed in Pandemic Studios, a video game company in Los Angeles, California.

Comments and Discussions