VS2010 创建动态链接库时遇到的问题

1 篇文章 0 订阅

动态调用

1、创建dll

(1)创建”win32工程“,并选中dll,点击完成

(2)添加CommStruts.h头文件,里面写有关于函数的结构体内容,如下:

 #pragma once

// 学生构造体
typedef struct {
    // 学生名称    
    char Name[8];
    // 学生年齢
    int Age; 
} Student; 

再添加含有函数体的文件ShowStudentInfo.cpp:内容如下:

#include "StdAfx.h"
#include <iostream>
#include "CommStruts.h"


using namespace std;


// 输出学生信息
int ShowStudentInfo(Student * stud)
{
    // 输出学生姓名
    cout<<"Name : "<<stud->Name<<endl;
    // 输出学生年龄
    cout<<"Age : "<<stud->Age<<endl;
    // 返回学生年龄
    return stud->Age;
}

接着再添加def文件CnBlogs.def(源文件目录下创建),内容如下:

LIBRARY CnBlogsDll
EXPORTS
ShowStudentInfo

在刚开始这个工程自己产生一个dllmain.cpp,这个相当于这个dll的如何函数(自动产生的)

最后在《生成》中选择”编译“,编译成功后选择”生成CnBlogsDLL“,如果成功的话,则在Debug文件夹里有lib/dll/ilk/pdb/exp/dll.manifest等后缀的文件

2、然后需要的在一般的程序里调用生成的DLL,这里我采用的是显示调用

这时候创建一个”WIN32控制台应用程序“ 命名为test,把上面生成的 "CommStruts.h"和”CnBlogsDll.dll“放入test工程下,接着在test工程目录下添加现有的"CommStruts.h"即可,然后编写test.cpp文件,里面代码为:

 // test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "CommStruts.h"
#include <Windows.h>
#include<iostream>
using namespace std;
int main(void)
{
typedef int(*pStu)(Student *stu);
HINSTANCE hDLL;
pStu pstu;
hDLL=LoadLibrary(_T("CnBlogsDll.dll"));
pstu=(pStu)GetProcAddress(hDLL,"ShowStudentInfo");
Student *stu1=(Student *)malloc(sizeof(Student));

strcpy(stu1->Name,"minus");
stu1->Age=12;
int age=pstu(stu1);
cout<<age<<endl;
FreeLibrary(hDLL);   //注意需要释放
getchar();
return 0;
这样就会调用成功!虽然这是最简单的一种,但还是可以让我们体会一下动态链接库的调用方法,为更复杂的动态链接库编写做好基础


编译、生成dll出现的问题有:

VS 2010下 打开实例 出现这样的错误:
LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

终极解决方案:

VS2010在经历一些更新后,建立Win32 Console Project时会出“error LNK1123” 错误,解决方案为将 项目|项目属性|配置属性|清单工具|输入和输出|嵌入清单 “是”改为“否”即可,但是没新建一个项目都要这样设置一次。
在建立VS2010 Win32 Project项目时,按照上面解决方案依然发生了“error LNK1123”错误,经过上网查资料,解决方案为:
第一步:与上相同。
第二步:将 项目|项目属性|配置属性|连接器|清单文件|嵌入清单 “是”改为“否”。
第三步:一般计算机经过上两步设置就能解决问题了,但是如果还有问题,那就按一下方法解决:
计算机是否为64bit操作系统,如是,继续2。
查找是否有两个cvtres.exe。一个是C:\Program Files(x86)\Microsoft Visual Studio 10.0\vc\bin\cvtres.exe, 另一个是C:\Windows\Microsoft.NET\Framework\v
4.0.30319\cvtres.exe。右键属性|详细信息 查看两者版本号,删除/重命名较旧的版本,或者重新设置Path变量。

意外的是,治本的办法是第三步,删除旧版本的cvtres.exe后,就不需要每次都设置配置了。


2、可能还会出现的小问题 是“在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "StdAfx.h”

 错误分析:
    此错误发生的原因是编译器在寻找预编译指示头文件(默认#include "stdafx.h")时,文件未预期结束。没有找到预编译指示信息的头文件"stdafx.h"。
    (因为工程中的每个cpp文件属性默认都是使用预编译头(/YU)的,但是添加的第三方文件并没有 #include "stdafx.h" 预编译指示头,所以编译器在此cpp文件中一直到末尾都没有找到它)
    我的这个问题发生于我通过添加文件的方式,向MFC内添加现有的一大坨.h和.cpp文件。这些.h和.cpp文件是属于标准C++的开源源代码范畴,与MFC无更深层次的关系。

解决方式:
一.
1) 在解决方案资源管理器中,右击相应的.cpp文件,点击“属性”
2) 在左侧配置属性中,点开“C/C++”,单击“预编译头”
3) 更改右侧第一行的“创建/使用预编译头”,把选项从“使用预编译头(/Yu)”改成“不使用预编译头”
4) 注:每一个报错的.cpp都要如此更改哦~辛苦一下呗~
二.
(不推荐)
1)在解决方案右击工程,点击属性
2)在配置属性 -> c/c++ -> 预编译头 中 将 “使用预编译头(/YU)” 改为 “不适用预编译头”
这种做法会使每次编译过程非常缓慢 


3、

那有没有什么工具能看到一个dll文件里有什么函数是导出函数呢? 答案是有的,在VC6.0中有一个叫Depends的图形界面工具可以查看,但是VS2010没有自带这个工具,但是有一个很好用的文本命令工具——dumpbin。打开VS2010的命令提示工具,用cd命令把目录切换到.dll的目录下,输入dumpbin -exports VCDLL.dll,就可以看到它的导出情况了,如下图:
TM截图20130601135012
中间那里可以看到导出的函数为add和sub。ordinal为函数的序号,hint表示提示码,rva是表示函数在dll中的地址,name表示函数名。

细心的读者可能会注意到,函数名有点怪,函数名被添加了很多奇怪的符号。这是因为在C++中为了支持函数重载,所以编译器在编译链接时,它往往会去篡改函数的名字,按照自己定义的法则去改变函数的名字。不同的C++的编译器定义的改名的法则并不相同,这就导致了一个严重的问题,就是用一个编译器编写的dll在另一个编译器中使用时,会因为改名的法则不同而找不到导出的函数,从而导致调用出错。解决的方法有很多种,下面再详述。

4、#include<windows.h>与#include<winsock2.h>在文件开始放的顺序也直接影响dll的生成,先放#include<winsock2.h>然后再放#include<windows.h>即可。否则出现的

 c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(91): warning C4005: “AF_IPX”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(460) : 参见“AF_IPX”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(131): warning C4005: “AF_MAX”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(479) : 参见“AF_MAX”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(168): warning C4005: “SO_DONTLINGER”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(402) : 参见“SO_DONTLINGER”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(212): error C2011: “sockaddr”:“struct”类型重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(485) : 参见“sockaddr”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(390): error C2059: 语法错误:“常量”
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(390): error C3805: “常量”: 意外标记,应输入“}”或者“,”
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(524): warning C4005: “IN_CLASSA”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(287) : 参见“IN_CLASSA”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(530): warning C4005: “IN_CLASSB”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(293) : 参见“IN_CLASSB”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(536): warning C4005: “IN_CLASSC”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(299) : 参见“IN_CLASSC”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(547): warning C4005: “INADDR_ANY”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(304) : 参见“INADDR_ANY”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(549): warning C4005: “INADDR_BROADCAST”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(306) : 参见“INADDR_BROADCAST”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\ws2def.h(583): error C2011: “sockaddr_in”:“struct”类型重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(312) : 参见“sockaddr_in”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\winsock2.h(132): error C2011: “fd_set”:“struct”类型重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(68) : 参见“fd_set”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\winsock2.h(167): warning C4005: “FD_SET”: 宏重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(102) : 参见“FD_SET”的前一个定义
1>c:\program files\microsoft sdks\windows\v7.0a\include\winsock2.h(176): error C2011: “timeval”:“struct”类型重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(111) : 参见“timeval”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\winsock2.h(232): error C2011: “hostent”:“struct”类型重定义
1>          c:\program files\microsoft sdks\windows\v7.0a\include\winsock.h(167) : 参见“hostent”的声明
1>c:\program files\microsoft sdks\windows\v7.0a\include\winsock2.h(245): error C2011: “netent”:“struct”类型重定义
的问题

静态调用

1、创建dll跟上面基本一样,不过在CommStruts.h中最后增加一行,该文件全部内容为:

 #pragma once

// 学生构造体
typedef struct {
    // 学生名称    
    char Name[8];
    // 学生年齢
    int Age; 
} Student;
_declspec(dllexport) int ShowStudentInfo(Student *stu);   //这句话可以在生成.dll文件的工程的 CommStruts.h下没有,但一定要在把这句话加在调用.dlll函数的工程test下的 CommStruts.h头文件里出现,否则test程序检测不到该函数。
其他都不变

2、不过要静态调用dll,调用程序需要.lib  /.dl   l/.h三个文件(CnBlogsDll.dll    CnBlogsDll.lib   及 CommStruts.h文件)放入到test文件目录下与.cpp同目录下

在项目->CnBlogsDll属性->属性配置->C/C++->常规->附加包含目录 中 添加 CommStruts.h的路径
Visual <wbr>Studio下建立并隐式调用自己的动态链接库dll

     在项目->CnBlogsDll属性->属性配置-链接器->常规->附加库目录  中添加  CnBlogsDll.lib  的目录
Visual <wbr>Studio下建立并隐式调用自己的动态链接库dll

     在项目->CnBlogsDll属性->属性配置-链接器->输入->附加依赖项  中添加    CnBlogsDll.lib  
Visual <wbr>Studio下建立并隐式调用自己的动态链接库dll
记得还要把dll文件放入test工程下,
然后与动态连接不同的是test.cpp文件中的内容,此处应该为(相比动态简单了很多):
 // test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "CommStruts.h"
#include <Windows.h>
#include<iostream>
using namespace std;
int main(void)
{
/*typedef int(*pStu)(Student *stu);
HINSTANCE hDLL;
pStu pstu;
hDLL=LoadLibrary(_T("CnBlogsDll.dll"));
pstu=(pStu)GetProcAddress(hDLL,"ShowStudentInfo");
*/  注释为动态连接需要的东西

Student *stu1=(Student *)malloc(sizeof(Student));
strcpy(stu1->Name,"minus");
stu1->Age=12;
int age=ShowStudentInfo(stu1);
cout<<age<<endl;

getchar();
return 0;
}

即可运行,
结果:
Name: minus
Age:12
12





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值