S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

dll调用引擎

Posted on 2010-03-11 08:28 S.l.e!ep.¢% 阅读(391) 评论(0)  编辑 收藏 引用 所属分类: VC

/////////////////////////////////////////////下面是使用此dll调用引擎的实例代码
CDllFunctionCall DllCall;
/*CHAR szTest1[]="Hello";
CHAR szTest2[]="Hello, World!";
std::vector<CDllVariable> Args;
Args.push_back(CDllVariable(long(0)));
Args.push_back(CDllVariable("Hello, World!"));
Args.push_back(CDllVariable("Hello!"));
Args.push_back(CDllVariable(MB_ICONINFORMATION | MB_YESNO));


INT iRetB=DllCall.Load("user32.dll","MessageBoxA");

if(FAILED(iRetB))
{
  AfxMessageBox("找不到相应函数入口");
  return ;
}
if(IDYES==(int)DllCall.Invoke(Args,CDllVariable::atInt).Data.IntVal)
{
  AfxMessageBox("检测到确定按钮");
}
else
{
  AfxMessageBox("检测到取消按钮");
}
DllCall.UnLoad();*/
DllCall.Load("Kernel32.dll","DeleteFileA");
std::vector<CDllVariable> Argss;
Argss.push_back("c:\\dd.txt");
BOOL bRet=DllCall.Invoke(Argss,CDllVariable::atInt).Data.IntVal;
if(bRet)
{
  AfxMessageBox("删除成功");
}
else
{
  AfxMessageBox("删除失败");
}

///////////////////////////////////////////下面是此类的头文件
#include <vector>class CDllVariable
{
public:
enum CDllVariableType
{
  atBool,
  atVoid,
  atInt,
  atChar,
  atWChar,
  atDouble,
  atFloat,
  atInt64
};
CDllVariableType Type;
union
{
  bool BoolVal;
  INT IntVal;
  CHAR CharVal;
  wchar_t WCharVal;
  DOUBLE DoubleVal;
  FLOAT FloatVal;
  __int64 Int64Val;
} Data;

CDllVariable();
CDllVariable(bool val);
CDllVariable(INT val);
CDllVariable(__int64 val);
CDllVariable(LONG val);
CDllVariable(FLOAT val);
CDllVariable(DOUBLE val);
CDllVariable(CHAR val);
CDllVariable(wchar_t val);
CDllVariable(LPCTSTR val);
CDllVariable(VOID * val);
};
class CDllFunctionCall  
{
public:
enum CallConvention
{
  ccStdCall,
  ccCdecl
};
public:
HRESULT Load(LPCSTR szDllPath,LPCTSTR szFuncName);
VOID UnLoad();
CDllVariable Invoke(std::vector<CDllVariable>& Args, CDllVariable::CDllVariableType ReturnType, CallConvention conv = ccStdCall);
private:
FARPROC FFuncPtr;
HMODULE m_hDllHandle;

public:
CDllFunctionCall();
virtual ~CDllFunctionCall();
};

///////////////////////////////////////////////////////下面是具体代码的实现


CDllFunctionCall::CDllFunctionCall()
{
}
CDllFunctionCall::~CDllFunctionCall()
{
}
CDllVariable::CDllVariable(bool val)
{
Type=atBool;
Data.BoolVal=val;
}
CDllVariable::CDllVariable( INT val )
{
Type = atInt;
Data.IntVal = val;
}
CDllVariable::CDllVariable(LONG val)
{
CDllVariable(__int64(val));
}
CDllVariable::CDllVariable(VOID * val)
{
CDllVariable(INT(val));
}
CDllVariable::CDllVariable()
{
Type = atVoid;
Data.IntVal = 0;
}
CDllVariable::CDllVariable( FLOAT val )
{
Type = atFloat;
Data.FloatVal = val;
}
CDllVariable::CDllVariable( DOUBLE val )
{
Type = atDouble;
Data.DoubleVal = val;
}
CDllVariable::CDllVariable( __int64 val )
{
Type = atInt64;
Data.Int64Val = val;
}
CDllVariable::CDllVariable( wchar_t val )
{
Type = atWChar;
Data.WCharVal = val;
}
CDllVariable::CDllVariable( CHAR val )
{
Type = atChar;
Data.CharVal = val;
}
//字符串用于传送地址进去
CDllVariable::CDllVariable(LPCTSTR val )
{
Type = atInt;
Data.IntVal =(INT)val;
}

HRESULT CDllFunctionCall::Load(LPCSTR szDllPath,LPCTSTR szFuncName)
{
m_hDllHandle=LoadLibrary(szDllPath);
if(!m_hDllHandle || m_hDllHandle==INVALID_HANDLE_VALUE)return -1;
FFuncPtr = GetProcAddress(m_hDllHandle,szFuncName);
if(!FFuncPtr)return -2;
return 0;
}
VOID CDllFunctionCall::UnLoad()
{
if(!FFuncPtr)FFuncPtr=NULL;

if(m_hDllHandle && m_hDllHandle!=INVALID_HANDLE_VALUE)
{
  FreeLibrary(m_hDllHandle);
  //CloseHandle(m_hDllHandle);
  m_hDllHandle=NULL;
}
}
CDllVariable CDllFunctionCall::Invoke(std::vector<CDllVariable>& Args, CDllVariable::CDllVariableType ReturnType, CallConvention conv )
{
if((!m_hDllHandle || m_hDllHandle==INVALID_HANDLE_VALUE) || (!FFuncPtr)) return CDllVariable(0);

  
// 用于存放8字节数据的结构
union LongType
{
  double DoubleVal;
  __int64 IntVal;
  struct  
  {
   int Head,Tail;
  } Parts;
};

// 使用stdcall/cdecl函数调用约定,参数从右至左压栈
for (int i=Args.size()-1; i>=0; i--)
{
  CDllVariable var = Args;
  LongType l;
  // 将单字节数据放在4字节变量中,以便入栈
  int tmp = var.Data.CharVal;
  // 将不同类型的数据压入堆栈
  switch(Args.Type)
  {
  case CDllVariable::atBool:
   {
    _asm push var.Data.BoolVal
   }
   break;
  case CDllVariable::atChar:  // 单字节整数
   __asm
   {
    push tmp
   };
   break;
  case CDllVariable::atDouble: // 8字节浮点
   // 8字节数据分两部分压入堆栈,低位先入栈
   l.DoubleVal = var.Data.DoubleVal;
   __asm
   {
    push l.Parts.Tail
    push l.Parts.Head
   }
   break;
  case CDllVariable::atFloat: // 4字节浮点
   __asm
   {
    push var.Data.FloatVal;
   }
   break;
  case CDllVariable::atInt: // 32位整数
   __asm push var.Data.IntVal;
   break;
  case CDllVariable::atWChar: // 16位整数
   __asm push var.Data.WCharVal;
   break;
  case CDllVariable::atInt64: // 64位整数
   l.IntVal = var.Data.Int64Val;
   __asm
   {
    push l.Parts.Tail
    push l.Parts.Head
   }
   break;
  case CDllVariable::atVoid: // 对于函数参数,void类型是非法的
  // throw gxException(gxString(L"Cannot pass void as an argument. (gxDllFunction::Invoke)"),__FILE__,__LINE__);
   break;
  }
}
// 嵌入式汇编只能访问函数内部变量,故将函数指针复制一份
FARPROC fptr = FFuncPtr;
// 调用函数,并获得保存在EDX,EAX中的整型函数返回值
LongType ltVal;
int itval, ihval;
__asm
{
  call fptr
  mov int ptr[ihval], EDX
  mov int ptr[itval], EAX
}
ltVal.Parts.Head = ihval; // 高位字只为int64类型所使用
ltVal.Parts.Tail = itval;

// 将函数返回值整理到gxDllVaraiable结构中
CDllVariable retval;
retval.Type = ReturnType;
switch (ReturnType)
{
case CDllVariable::atChar:
  retval.Data.CharVal = ltVal.Parts.Tail;
  break;
case CDllVariable::atDouble:
  // 对于浮点类型返回值,需从FPU堆栈的栈顶中读取
  __asm fstp [retval.Data.DoubleVal];
  break;
case CDllVariable::atFloat:
  // 对于浮点类型返回值,需从FPU堆栈的栈顶中读取
  __asm fstp [retval.Data.FloatVal];
  break;
case CDllVariable::atInt:
  retval.Data.IntVal = ltVal.Parts.Tail;
  break;
case CDllVariable::atWChar:
  retval.Data.WCharVal = ltVal.Parts.Tail;
  break;
case CDllVariable::atInt64:
  retval.Data.Int64Val = ltVal.IntVal;
  break;
case CDllVariable::atVoid:
  break;
}
// 使用C/C++默认调用约定,需要由调用者弹出变量
if (conv == ccCdecl)
{
  for (int i=0; i<Args.size(); i++)
  {
   if (Args.Type == CDllVariable::atDouble || Args.Type == CDllVariable::atInt64)
   __asm
   {
    pop EAX
    pop EAX
   }
   else
   __asm
   {
    pop EAX
   }
  }
}
return retval;
}


说明:在系统中加入这个接口,基本上等于实现了什么东西都可以调用别人的程序,不必自己实现,根据业务的多变情况
     随时调用相应的功能DLL即可实现,做为程序员的明确目标:写最少的程序!


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理