首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > VSTS >

VS2008环境上,C++生成Dll文件C++调用Dll文件(非MFC)

2012-10-11 
VS2008环境下,C++生成Dll文件C++调用Dll文件(非MFC)生成Dll文件新建项目,选择Win32项目,工程名:09DllDemo

VS2008环境下,C++生成Dll文件C++调用Dll文件(非MFC)
生成Dll文件
新建项目,选择Win32项目,工程名:09DllDemo 确定后,选择应用程序设置, 应用程序类型选择DLL(D),附加选项上选择 导出符号(X)(便于学习)。单击完成,完成工程创建。
-----------------------------------------
打开 09DllDemo.cpp文件,因为选择导出符号的缘故,VC++自动给我们生成了
// 这是导出函数的一个示例。
extern "C"
{
// 这是导出函数的一个示例。
MY09DLLDEMO_API int fnMy09DllDemo()
{
   return 42;
}
}
打开 09DllDemo.h 我们可以看到声明的函数。
//声明要导出的函数
extern "C"
{
MY09DLLDEMO_API int fnMy09DllDemo();
}
---------------------------------------------
我们自己要添加入的函数按上述格式添加就可以了。(加extern "C"能保证导出的Dll函数名不会变化。这里的描述可能有点问题)
选中项目,点生成,生成Dll文件的任务就完成了。最后09DllDemo工程产生的文件中有3个可以被其他工程所使用:09DllDemo.h 09DllDemo.dll 09DllDemo.lib。
.dll文件就是动态链接库,.lib是供程序开发用的导入库,.h文件包含了导出函数的声明。
调用Dll文件
调用Dll中的导出函数有两种方法:
1.装载期间动态加载。
模块可像调用本地函数一样调用从其他模板导出的函数(API函数就是这样调用的)。装载期间链结必须使用DLL的导入库(.lib)文件,它为系统提供了加载这个Dll和定位Dll中的导出函数所需的信息。
应用程序启动时由载入器(加载应用程序的组件)载入09DllDemo.dll文件。载入器如何知道要载入哪些Dll呢?这些信息记录在执行文件(PE文件)的idata节中。使用这种方法不用自己写代码显式加载DLL。
---------------------------
新建一个09ImportDemo的Win32控制台工程,将09DllDemo.h,09DllDemo.lib,09DllDemo.dll 3个文件拷贝到09ImportDemo目录下。
下面给出了调用导出函数fnMy09DllDemo的代码
#include "09DllDemo.h"
#include <iostream>
using namespace std;
#pragma comment(lib,"09DllDemo")
void main()
{
int a =fnMy09DllDemo();
cout<<a<<endl;
}
发布软件时必须将该软件使用的Dll与主程序一起发布。09ImportDemo.exe和09DllDemo.dll放在同一个目录下。载入器加载Dll文件时,默认情况是在应用程序的当前目录下查找,如果找不到就到系统盘"\windows\system32"文件夹下查找,还找不到就按错误处理。
--------------------------------------------------------------------------
2.运行期间动态加载。(只需Dll文件即可)
运行期间动态加载是在程序运行过程中显式得加载Dll库,从中导出需要的函数。
为了能够在运行期间动态导出函数,一般需要在09DllDemo工程中建立一个DEF文件来指定要导出的函数。
----添加DEF文件
打开09DllDemo工程,右键点击工程,选择添加,选择TextFile选项,输入文件名DllDemo.def
新的DllDemo.def中添加如果内容
=============================
EXPORTS
        fnMy09DllDemo
=============================
重新生成下就完成了。
回到09ImportDemo工程,将程序修改为
------------------------------------------------------
#include <windows.h>
#include <iostream>
using namespace std;
//定义FunctionFunc为指向一个返回值为int型 无参数的函数的指针
typedef int (*FunctionFunc)();
int main()
{
   FunctionFunc _FunctionFunc;
   //加载目标Dll
   HMODULE hModule = ::LoadLibrary(TEXT("D:\\09DllDemo.dll"));
   if (hModule==NULL)//如果Dll加载失败,释放它占用的资源
   {
    ::FreeLibrary(hModule);
   }
   //取得目标Dll中导出函数的地址(提醒:函数名就是函数的入口地址)
   _FunctionFunc=(FunctionFunc)::GetProcAddress(hModule,"fnMy09DllDemo");
   if (_FunctionFunc==NULL)
   {
    ::FreeLibrary(hModule);
   }
   int a =_FunctionFunc();
   cout<< a<<endl;
   ::FreeLibrary(hModule);
   cin.get();
   return 1;

}
------------------------------------------------------
c#中调用Dll
[DllImport("D:\\09DllDemo.dll")")]
        public static extern int fnMy09DllDemo();
------------------------------------------------------
备注:
在没加extern "C"生成的Dll的函数名会有变化,因此在运行期间动态链结过程中,调用GetProcAddress会返回空值。
如不能修改Dll源码,可采用下面的方式解决(比较笨的方法,有好的请留言,谢谢):先用Depends.Exe(VS自带的工具)打开Dll文件,右键点击函数复制函数名。如获得的函数名为
?fnMy09DllDemo@@YAHXZ
C++中 直接
_FunctionFunc=(FunctionFunc)::GetProcAddress(hModule,?fnMy09DllDemo@@YAHXZ);
c#中
[DllImport("D:\\09DllDemo.dll", EntryPoint = "?fnMy09DllDemo@@YAHXZ")]
public static extern int fnMy09DllDemo();

热点排行