描述:
实现c++下类似com下的IDispatch接口类。
特征如下
Class CDispatch
{
CDispatch("dispatch_name");
//通过名称注册回调函数
reg_func("fucn_name",callback_func);
//调用类似IDispatch的Invoke
Invoke(("func_name",result_val,parme_num,...);
}
要求:
1,返回值可是用VARIANT类型或自己实现.
2,new出的同一dispatcvh name的实例,可以任意c++模块中调用,可以不需要跨语言
3,跨线程安全调用.
调用例子如下:
A模块中:
//全局函数func_1;
int fun_1(int i,char * c)
{
return i;
}
CDispatch a("dis");
a.reg_func("func1",fun_1);
B模块中:
CDispatch b("dis");
VARIANT v;
b.Invoke("func1",&result,2,1,"teststr");
解决方案1:
使用回调函数。有很多现成的方法。
解决方案2: 这个类的主要作用在于减少模块间的耦合关系.用于作plug-in实现大致与COM组件类似.
在任何模块中可以调用己发布的函数(即通过己注册的函数名),而不需要从别处引根指针进来调用该函数。
------------------------------------------------------------------------------------
您的意思是:
MODULE A :实现并注册了一个函数 global_func()
MODULE B : 需要调用这个global_func()
MODULE Dispatch :负责函数的注册和调用。
那MODULE B只根据注册的函数名怎样知道这个函数的返回值和参数列表呢?如果不知道的话,它的Invoke怎样call呢?这个注册的步骤是否缺少了些什么呢?
#include "string"
#include "vector"
#include"map"
using namespace std;
typedef void (* proc)(long* pRtn,...);
class MyDispatch ;
class DispatchManager
{
vector<MyDispatch*> array;
public:
void Add(MyDispatch* p)
{
array.push_back(p);
}
MyDispatch* FindDispatch(string pName);
DispatchManager(){}
};
DispatchManager * g_pManager ;
bool InitMyLib(){
if( g_pManager == NULL )
{ g_pManager = new DispatchManager() ;
return 1;
}
return 0;
}
void DeleteMyLib(){
if( g_pManager)
delete g_pManager ;
g_pManager = NULL;
return ;
}
class MyDispatch
{
private:
string m_cName ;
map<string,proc> m_cFunArray;
static string m_cFindName;
public:
proc FindProc(string name)
{
return NULL;
}
bool IsName(string name)
{
if( m_cName == name )
return 1;
return 0;
}
MyDispatch(string pName)
{
m_cFindName = pName ;
m_cName = pName ;
}
void * operator new (unsigned int size)
{
MyDispatch* pRtn = NULL;
if( pRtn = g_pManager->FindDispatch(m_cFindName))
{
return pRtn ;
}
return malloc(size* sizeof( MyDispatch) ) ;
}
void RegFun(string pFunName,proc p)
{
pair<string ,proc> par ;
par =make_pair(pFunName,p) ;
m_cFunArray.insert(par);
}
bool Invoke(string pFunName,long* pRtn ,int i)
{
proc pc = (proc)FindProc(pFunName) ;
pc(pRtn,i);
return 1;
}
};
MyDispatch* DispatchManager::FindDispatch(string pName)
{
vector<MyDispatch*>::iterator pFirst ,pEnd ;
pFirst = array.begin();
pEnd = array.end();
while( pFirst != pEnd)
{
MyDispatch* p = (MyDispatch*)*pFirst ;
if( p->IsName(pName) )
return p ;
pFirst ++ ;
}
return 0;
}
呵呵,漏了一个virtual,现在补上 :)
virtual VARIANT InvokeImpl(VARIANT* pArgs, int nArgCount)=0;
顺便问句,实现这个与模拟JNI有关吗? :)
我也有想过这个问题,如果函数fun_1的参数个数以及类型不是固定的,用这样的写法来调用CDispatch接口,这个CDispatch接口很难实现,难点在于CDispatch里面不能正确的知道函数fun_1的形态,因而不能正确的调用这个函数。
个人建议是固定函数fun_1的参数个数以及类型,如:
VARIANT fun_1(VARIANT* pArgs,int nArgCount);
还有一个方法是改变reg_func的参数,不是直接把fun_1传进去,而是把一个回调的接口传进去,这个回调的接口由实现CDispatch的人声明,而由CDispatch的使用者实现.由于这个中间接口的形态是固定的,所以CDispatch可以处理,而由于这个中间接口是由使用者实现的,所以它可以转调用任何形态的函数,完全看使用者的需要.如:
class IFuncCallBack
{
public:
VARIANT InvokeImpl(VARIANT* pArgs, int nArgCount)=0;
};
Class CDispatch
{
public:
bool reg_func(string sFuncName, IFuncCallBack* pFuncImpl);
};
函数的参数个数以及类型是固定的?
解决方案7:就只有用DLL才能实现吧,如用EXE那可就复杂多了.
解决方案8:应该不算很难,但跨线程这点上我还没完全搞懂.怎样才能跨.
解决方案9: // testcons3.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <map>
#include <string>
#include "stdlib.h"
#include "stdarg.h"
#include "conio.h"
#include "comutil.h"
#pragma comment(lib, "comsupp.lib")
class CDispatch;
typedef std::map<std::string, void*> DISP_TABLE;
typedef _variant_t (*FUNCTYPE1)(_variant_t v1);
typedef _variant_t (*FUNCTYPE2)(_variant_t v1, _variant_t v2);
_variant_t func1(_variant_t i)
{
printf("func1(%d)\n", (int)i);
return _variant_t(0);
}
_variant_t func2(_variant_t i, _variant_t j)
{
printf("func2(%d,%d)\n", (int)i, (int)j);
return _variant_t(1);
}
class CDispCritical
{
private:
CRITICAL_SECTION m_Sect;
public:
CDispCritical()
{
::InitializeCriticalSection(&m_Sect);
}
~CDispCritical()
{
::DeleteCriticalSection(&m_Sect);
}
void Lock()
{
::EnterCriticalSection(&m_Sect);
}
void Unlock()
{
::LeaveCriticalSection(&m_Sect);
}
};
class CDispLock
{
private:
CDispCritical *m_pSect;
public:
CDispLock(CDispCritical& sect)
{