在写C++程序时,时常需要将一个class写成DLL,供客户端程序调用。这样的DLL可以导出整个class,也可以导出这个class的某个方法。
一、导出整个class
方法很简单,只需要在类的头文件中class和类名之间加上_declspec(dllexport),同时在另外一份提供给客户端调用程序使用的类的头文件中class和类名之间加上_declspec(dllimport)。为了能让客户端程序和DLL程序公用该类的一份头文件,通常在类的头文件中使用宏和预编译指令来处理。如下DLLTest.h:
#ifdef DLL_TEST_API
#else
#define
DLL_TEST_API _declspec(dllimport)
#endif
Class DLL_TEST_API CDLLTest
{
Public:
CDLLTest()
~CDLLTest()
int Add(
int
a, int
b)
}
DLLTest.cpp如下:
#define
DLL_TEST_API _declspec(dllexport)
#include “DLLTest.h”
………………………………………
这样,在DLL编译时DLL_TEST_API被定义为_declspec(dllexport),而且客户端程序编译时它被定义为_declspec(dllimport)。
二、导出这个类的某个或者某几个方法。
这时,需要将_declspec(dllexport)放到成员函数名前,如DLLTest.h:
#ifdef DLL_TEST_API
#else
#define
DLL_TEST_API _declspec(dllimport)
#endif
Class CDLLTest
{
Public:
CDLLTest()
~CDLLTest()
int DLL_TEST_API Add(
int
a, int
b)
}
但是,如果仅仅是这样的话,当客户端程序#include这个头文件后,定义DLLTest这个类的一个对象后(静态方式链接DLL),客户端程序无法链接通过,会提示构造函数和析构函数无法解析,此时,需要将构造函数和析构函数前也加上DLL_TEST_API宏即可。
当然这里还有个问题就是类的函数在导出后,名字会发生变化,我们可以在函数名前再加上extern “C” ,如 extern “C” DLL_TEST_API int Add(int a ,int b)但这只解决了C与C++调用时名字变更问题,可靠的方法还是增加一个模块定义文件def,在该文件中定义导出函数的名称,我们将在后面看到样例。
DLL编写完成后,就只剩下客户端程序如何去调用该DLL了,静态方式调用DLL和动态方式调用DLL。
一、静态方式调用DLL
这个方法就简单了,将DLLTest.h头文件和DLLTest.lib,DLLTest.dll文件拷贝到客户端程序的当前目录下,在客户端程序中#include<DLLTest.h>,然后通过#pragma comment(lib,”DLLTest.lib”)的方式引入lib库,或者在客户端程序的工程属性里面增加对该lib文件的引入。
然后就可以在客户端程序中如同使用本地的一个class一样使用该DLL了,如:
CDLLTest dllTest
dllTest.Add(
1
,2
)
二、动态方式调用DLL
动态调用这个DLL,就需要对这个class进行修改了。
首先,在DLLTest.cpp文件中增加一个全局函数,该函数可以返回这个class的一个实例,这样,客户端程序调用这个全局函数后,得到该class的实例,就可以调用该class的实例方法了。
extern
“C” _declspec(dllexport) CDLLTest* GetInstance()
{
return
new
CDLLTest
}
注:extern “C” 只是解决了c与c++编译器之间的兼容问题,如果需要和其他编译器之间兼容,可靠的办法还是增加一个.def文件,文件内容如下:
LIBRARY “DLLTest”
EXPORTS
GetInstance
= GetInstance
这样就指定了DLL的函数导出后的名称仍然不变。
这样,客户端程序就可以通过该函数来获取class的一个实例了。如下:
先需要定义一个函数指针类型:
typedef CDllTestBase* (*pfGetInst)()
//
注:CDllTestBase类后面会介绍。
HMOUDLE hMod
= LoadLibrary( _T(“DLLTest.DLL”) )
if(hMod)
{
pfGetInst pfGetInstance
= (pfGetInst)GetProcAddress(“GetInstance”)
if( p )
{
//
通过基类指针指向派生类对象
CDllTestBase * pInst = pfGetInstance ()
if( NULL
!= pInst )
{
pInst
->Add( 1
,2
)
}
if( NULL
!= pInst )
{
//
释放对象
delete pInst
}
}
}
当然,这里还是需要include这个DLL的头文件DLLTestBase.h,如果将之前所写的头文件DLLTest.h直接拷贝到客户端程序的当前目录下,并include进来的话,在编译连接时,是无法通过的,我们需要对这个头文件进行修改,首先增加一个.h 文件DLLTestBase.h,在这个文件中我们将需要在客户端程序中调用的函数都命名成纯虚函数,然后让CDLLTest类继承自CDLLTestBase类,DLLTestBase.h如下:
Class CDLLTestBase
{
Public:
Virtual
~CDLLTestBase(){}//
虚析构函数,且为内联函数
Virtual int
Add(int
a, int
b) = 0
}
DLLTest.h修改后如下:
#include “DLLTestBase.h”
Class CDLLTest :
public
CDLLTestBase
{
Public:
CDLLTest()
~CDLLTest()
int
Add(int
a, int
b)
}
注:这里的DLLTestBase需要提供一个虚析构函数,这样在客户端程序中就可以通过基类指针来释放派生类对象了。
这样,只需要将DLLTestBase.h拷贝到客户端程序的当前目录下,然后在客户端程序中#include”DLLTestBase.h”,就可以如上面介绍一样在客户端程序中调用DLL里面的方法了。
使用C#生成dll文件并调用一、创建dll文件:
例如生成一个md5编码判断状态的文件,即,输入一个字符串(string A)和一个32位md5编码(string B),判断此字符串A对应的32位md5编码是否与B相等,如果相等返回true,否则返回false。
打开VS 2005,“文件”--》“新建”--“项目”,选择“Windows 控件库”,命名后点击“确定”,在“UserControl1.cs”中输入以下代码:
using System
using System.Collections.Generic
using System.ComponentModel
using System.Drawing
using System.Data
using System.Windows.Forms
using System.Text
using System.Security.Cryptography
namespace md5
{
public partial class Program : UserControl
{
#region MD5 32位加密:GetMd5Str32
/// <summary>
/// 32位MD5加密
/// </summary>
/// <param name="strSource">待加密字串</param>
/// <returns>加密后的字串</returns>
public static string GetMd5Str32(string strSource)
{
byte[] bytes = Encoding.ASCII.GetBytes(strSource)
byte[] hashValue = ((System.Security.Cryptography.HashAlgorithm)System.Security.Cryptography.CryptoConfig.CreateFromName("MD5")).ComputeHash(bytes)
StringBuilder sb = new StringBuilder()
for (int i = 0i <16i++)
{
sb.Append(hashValue[i].ToString("x2"))
}
return sb.ToString().ToUpper()
}
#endregion
#region 核对md5编码是否一致:CheckMd5String()
/// <summary>
/// 核对md5编码是否一致
/// </summary>
/// <param name="ConvertString"></param>
/// <returns>如果一致返回true,否则返回false</returns>
///
public static bool CheckMd5String(string str1, string str2)
{
string md5String = str1//需要验证的字符串
string md5DbString = str2//需要核对的32位md5编码
int result = string.Compare(md5.Program.GetMd5Str32(str1), md5DbString, true)
if (result == 0)
{
return true
}
else
{
return false
}
}
#endregion
}
}
修改“UserControl1.Designer.cs”中的命名空间为“md5”,方法为“Program”,即可生成dll文件。
在...\bin\Debug文件假下,可以找到相应的dll文件。
二、部署dll流程:
首先把dll文件放到应用程序...\bin\Debug\下;
然后在解决方案中添加引用:右键鼠标-->添加引用-->浏览-->选择dll放置路径后点击“确定”。
注意:要在应用文件头处使用using md5;命令。
测试应用程序代码,如下:Form1.cs
using System
using System.Collections.Generic
using System.ComponentModel
using System.Data
using System.Drawing
using System.Text
using System.Windows.Forms
using md5
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent()
}
private void button1_Click(object sender, EventArgs e)
{
string str1 = textBox1.Text.ToString()
string md5String = textBox2.Text.ToString()
textBox3.Text = md5.Program.GetMd5Str32(str1)
textBox4.Text = md5.Program.CheckMd5String(str1, md5String).ToString()
}
private void button2_Click(object sender, EventArgs e)
{
this.Close()
}
}
}
创建新的动态链接库 (DLL) 项目从 “文件”菜单中,选择 “新建”,然后选择 “项目…”。
在 “项目类型”窗格中,选择 “Visual C++”下的 “Win32”。
在 “模板”窗格中,选择 “Win32 控制台应用程序”。
为项目选择一个名称,如
MathFuncsDll,并将其键入 “名称”字段。 为解决方案选择一个名称,如
DynamicLibrary,并将其键入 “解决方案名称”字段。
单击 “确定”启动 Win32 应用程序向导。
在 “Win32 应用程序向导”对话框的 “概述”页中,单击 “下一步”。
在 “Win32 应用程序向导”中的 “应用程序设置”页中,选择 “应用程序类型”下的 “DLL”(如果可用),或者选择 “控制台应用程序”(如果 “DLL”不可用)。 某些版本的 Visual Studio
不支持通过使用向导创建 DLL 项目。您可以稍后对此进行更改,以将项目编译为
DLL。
在 “Win32 应用程序向导”的 “应用程序设置”页中,选择 “附加选项”下的 “空项目”。
单击 “完成”创建项目。
向动态链接库添加类
若要为新类创建头文件,请从 “项目”菜单中选择 “添加新项…”。
将显示 “添加新项”对话框。
在 “类别”窗格中,选择 “Visual C++”下的 “代码”。 在 “模板”窗格中选择 “头文件(.h)”。 为头文件选择一个名称,如
MathFuncsDll.h,并单击 “添加”。 将显示一个空白文件。
添加一个名为“MyMathFuncs”的简单类,以执行常见的算术运算,如加、减、乘和除。代码应与以下内容类似:
以带有颜色区分的格式查看复制到剪贴板打印
// MathFuncsDll.h
namespace MathFuncs
{
class MyMathFuncs
{
public:
// Returns a + b
static __declspec(dllexport) double Add(double a, double b)
// Returns a - b
static __declspec(dllexport) double Subtract(double a, double b)
// Returns a * b
static __declspec(dllexport) double Multiply(double a, double b)
// Returns a / b
// Throws DivideByZeroException if b is 0
static __declspec(dllexport) double Divide(double a, double b)
}
}
// MathFuncsDll.h
namespace MathFuncs
{
class MyMathFuncs
{
public:
// Returns a + b
static __declspec(dllexport) double Add(double a, double b)
// Returns a - b
static __declspec(dllexport) double Subtract(double a, double b)
// Returns a * b
static __declspec(dllexport) double Multiply(double a, double b)
// Returns a / b
// Throws DivideByZeroException if b is 0
static __declspec(dllexport) double Divide(double a, double b)
}
}
请注意此代码方法声明中的 __declspec(dllexport) 修饰符。 这些修饰符使 DLL
能够导出该方法以供其他应用程序使用。有关更多信息,请参见 dllexport, dllimport。
若要为新类创建源文件,请从 “项目”菜单中选择 “添加新项…”。
将显示 “添加新项”对话框。
在 “类别”窗格中,选择 “Visual C++”下的 “代码”。 在 “模板”窗格中,选择 “C++ 文件(.cpp)”。 为源文件选择一个名称,如
MathFuncsDll.cpp,并单击 “添加”。 将显示一个空白文件。
在源文件中实现“MyMathFuncs”的功能。代码应与以下内容类似:
以带有颜色区分的格式查看复制到剪贴板打印
// MathFuncsDll.cpp
// compile with: /EHsc /LD
#include "MathFuncsDll.h"
#include <stdexcept>
using namespace std
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw new invalid_argument("b cannot be zero!")
}
return a / b
}
}
// MathFuncsDll.cpp
// compile with: /EHsc /LD
#include "MathFuncsDll.h"
#include <stdexcept>
using namespace std
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw new invalid_argument("b cannot be zero!")
}
return a / b
}
}
若要将项目生成为 DLL,请从
“项目”菜单中选择
MathFuncsDll “属性...”。 在左窗格中,选择 “配置属性”下的 “常规”。
在右窗格中,将 “配置类型”更改为 “动态库(.dll)”。
单击 “确定”保存更改。
说明
如果您从命令行生成项目,请使用
/LD 编译器选项指定输出文件应为 DLL。
有关更多信息,请参见 /MD、/MT、/LD(使用运行库)。
编译该动态链接库,方法是选择
“生成”菜单中的 “生成解决方案”。
这样就创建了一个可供其他程序使用的
DLL。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)