using System;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyLib
{
// Class that exports a single static function
public class MyClass
{
public MyClass(){}
static public void SayHello(String who)
{
Console.WriteLine("Hello, world, from {0}", who);
}
}
}
#using <mscorlib.dll>
#using <System.dll>
#include <vcclr.h>
#include <stdio.h>
#include <tchar.h>
using namespace System;
using namespace System::Reflection;
void main ()
{
try {
// Load library dynamically:
Assembly* a = Assembly::Load("MyLib");
if (a) {
Console::WriteLine("Assembly = {0}", a);
Type* t = a->GetType("MyLib.MyClass");
if (t) {
Console::WriteLine("Type = {0}", t);
MethodInfo* m = t->GetMethod("SayHello");
if (m) {
Console::WriteLine("Method = {0}\n", m);
String* args[] = {"Test2"};
m->Invoke(NULL, args);
} else {
printf("Can't find SayHello!\n");
}
} else {
printf("Can't find MyLib.MyClass!\n");
}
} else {
printf("Can't load MyLib!\n");
}
} catch (Exception* e) {
Console::WriteLine("*** Oops: Exception occurred: {0}", e);
}
}
Figure 4 ITextPlugin
#pragma once
using namespace System;
using namespace System::ComponentModel;
namespace TextPlugin {
// plug-in interface definition
public __gc __interface ITextPlugin
{
[ReadOnly(true)]
__property String* get_MenuName();
[ReadOnly(true)]
__property String* get_MenuPrompt();
String* Transform(String* text);
};
}
#pragma once
#include <vector>
using namespace std;
using namespace System;
using namespace System::Collections;
// STL vector of managed Objects, wrapped as gcroot handle
typedef vector <gcroot<Object*> > PLUGINLIST;
////////////////
// .NET Plug-in Manager. This class will load all the DLLs in a folder,
// looking for assemblies that contain classes that implement a specific
// interface, and will instantiate any such classes it finds, adding them
// to a list (STL vector). Note this is a native class, which is why I
// have to use gcroot, because a native class can't hold pointers to
// managed objects.
//
class CPluginMgr {
public:
CPluginMgr(LPCTSTR dir=NULL);
virtual ~CPluginMgr();
PLUGINLIST m_objects; // list (vector) of plug-in objects
// load all DLLs that implement given interface.
int LoadAll(Type* iface, int nReserve=10);
// Get ith plug-in
Object* CPluginMgr::GetPlugin(int i)
{
return m_objects[i];
}
// ditto, using []
Object* operator[](int i)
{
return GetPlugin(i);
}
protected:
// helper: load single plug-in
int LoadPlugin(Type* iface, LPCTSTR pathname);
CString m_dir; // plug-in directory where DLLs are
};
PluginMgr.cpp
#include "stdafx.h"
#include "PluginMgr.h"
using namespace System;
using namespace System::Reflection;
CPluginMgr::CPluginMgr(LPCTSTR dir) : m_dir(dir)
{
if (m_dir.IsEmpty()) {
// default plug-in directory is exedir/PlugIns, where exedir is the
// folder containing the executable
LPTSTR buf = m_dir.GetBuffer(MAX_PATH); // buffer in which to copy
GetModuleFileName(NULL, buf, MAX_PATH); // exe path
PathRemoveFileSpec(buf); // remove file name part
m_dir.ReleaseBuffer(); // free buffer
m_dir += _T("\\PlugIns"); // append "PlugIns"
}
}
CPluginMgr::~CPluginMgr()
{
}
//////////////////
// Load and instantiate all plug-ins that implement a given interface. Note
// this will load all DLLs in the plug-in directory, even ones that don't
// implement the interface—there's no way to unload an Assembly w/o using
// AppDomains.
//
int CPluginMgr::LoadAll(Type* iface, int nReserve)
{
ASSERT(iface);
ASSERT(iface->IsInterface);
m_objects.reserve(nReserve); // for efficiency
// Use MFC to find *.dll in the plug-ins directory, and load each one
CFileFind libs;
CString spec;
spec.Format(_T("%s\\*.dll"), m_dir);
TRACE(_T("Loading %s\n"), spec);
BOOL bMore = libs.FindFile(spec);
while (bMore) {
bMore = libs.FindNextFile();
LoadPlugin(iface, libs.GetFilePath());
}
TRACE(_T("%d plugins found\n"), m_objects.size());
return m_objects.size();
}
//////////////////
// Load single DLL file, looking for given interface
//
int CPluginMgr::LoadPlugin(Type* iface, LPCTSTR pathname)
{
int count=0;
try {
Assembly * a = Assembly::LoadFrom(pathname);
Type* types[] = a->GetTypes();
for (int i=0; i<types->Length; i++) {
Type *type = types[i];
if (iface->IsAssignableFrom(type)) {
TRACE(_T("Found type %s in %s\n"), CString(type->Name),
pathname);
Object* obj = Activator::CreateInstance(type);
m_objects.push_back(obj);
count++;
}
}
} catch (Exception* e) {
TRACE(_T("*** Exception %s loading %s, ignoring\n"),
CString(e->ToString()), pathname);
}
if (!count)
TRACE(_T("*** Didn't find %s in %s\n"), CString(iface->Name),
pathname);
return count;
}
#include "StdAfx.h"
#include "View.h"
#include "PGEdit.h"
#using <TextPlugin.dll>
using namespace TextPlugin;
IMPLEMENT_DYNCREATE(CMyView, CEditView)
BEGIN_MESSAGE_MAP(CMyView, CEditView)
ON_COMMAND_RANGE(IDC_PLUGIN_BASE, IDC_PLUGIN_END, OnPluginCmd)
ON_UPDATE_COMMAND_UI_RANGE(IDC_PLUGIN_BASE, IDC_PLUGIN_END,
OnPluginCmdUI)
END_MESSAGE_MAP()
void CMyView::OnPluginCmd(UINT id)
{
CEdit& edit = GetEditCtrl();
int begin,end;
edit.GetSel(begin,end);
if (end>begin) {
Object* obj = theApp.m_plugins.GetPlugin(id - IDC_PLUGIN_BASE);
ASSERT(obj);
ITextPlugin* plugin = dynamic_cast<ITextPlugin*>(obj);
if (plugin) {
CString text;
edit.GetWindowText(text);
text = text.Mid(begin, end-begin);
text = plugin->Transform(text);
edit.ReplaceSel(text);
edit.SetSel(begin,end);
}
}
}
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using TextPlugin;
public class CapsPlugin : ITextPlugin
{
public CapsPlugin() {}
public String MenuName
{
get { return "Uppercase"; }
}
public String MenuPrompt
{
get { return "Convert selected text to ALL UPPERCASE"; }
}
public String Transform(String text)
{
return text.ToUpper();
}
}