VC6.0 Win32动态链接库的创建与调用

动态链接库相比与静态链接库,所占用的内存空间小,较少交换时间,生成的dll文件也小,而且相应速度也快,静态链接库是将DLL程序为每一个应用程序装载一个副本程序,而动态链接库在多个文件同步使用一个DLL的共享内存中副本。

动态链接库分为Win32 DLL 和 MFC DLL,而后者又分为静态链接的常规DLL ,动态链接的DLL 和 扩展DLL。
一: Win32DLL

方法一:使用__declspec(dllexport) 导出

1)创建 Win32 dynamic library 取工程名称CreateWin32DLL, 选择
a dll that exports some symbols(该方法提供一些APIENTRY DllMain信息,不用在输入了)
2)为了很好的归类,新添加一个类,全部导出函数在这个类中。
类视图中 add new class 名称为CExportDll (一般类名开头为C)
3)新添加类 代码如下:
头文件中:
// ExportDll.h: interface for the CExportDll class.
//
//

#if !defined(AFX_EXPORTDLL_H__F99856A6_8485_4044_A526_1482DADE0ADE__INCLUDED_)
#define AFX_EXPORTDLL_H__F99856A6_8485_4044_A526_1482DADE0ADE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CExportDll
{
public:
CExportDll();
virtual ~CExportDll();
};//此段可以删除
extern “C” __declspec(dllexport) int Add(int a, int b);
extern “C” _declspec(dllexport) int Subtract(int a, int b);
#endif // !defined(AFX_EXPORTDLL_H__F99856A6_8485_4044_A526_1482DADE0ADE__INCLUDED
)

cpp中
// ExportDll.cpp: implementation of the CExportDll class.
//
//

#include “stdafx.h”
#include “ExportDll.h”

//
// Construction/Destruction
//

CExportDll::CExportDll()//可删除
{
}

CExportDll::~CExportDll()//可删除
{
}

extern “C” __declspec(dllexport) int Add(int a, int b)
{
return a + b;
}
extern “C” __declspec(dllexport) int Subtract(int a, int b)
{
return a - b;
}

注意事项:

  1. DLL中尽量不要导出 数据变量
    2)有 visual assist中 关键字是 蓝色的,在编写win32DLL时 出现了
    error C2065: ‘dllexport’ : undeclared identifier
    【解决方法】最后发现是关键字declspec写错了,导致出错
    extern “C” __delcspec(dllexport) int Subtract(int a, int b);
    应该为 extern “C” __declspec(dllexport) int Subtract(int a, int b);
    extern “C” 是c++编译器在编译函数时告诉要用c编译器的方式处理函数名。
    3)在测试win32DLL时,要.h,lib dll缺一不可,后两者名称与工程名称相同,.h是含 __declspec的自定义的头文件。添加完毕后出现问题:
    fatal error LNK1104: cannot open file “CreateWin32DLL.obj”
    【解决方法】1.忘记引用 dll的头文件了 ;2.设置项目属性时,Link中 Lib名称没有带.lib,写成了CreateWin32DLL。这两种情况下都会出现这个问题。
    只要修改了DLL,最好将dll lib .h都重新拷贝下。。。
    4)extern “C” 返回类型 __declspec(dllexport) 函数名称(形参)
    或者:extern “C” __declspec(dllexport) 返回类型 函数名称(形参) 都可以,但尽量用第二种,这样可以很方便的把extern “C” __declspec(dllexport) 定义成一个宏定义。
    但需要注意的是,extern "C"好像不能出现中Class CExportDll中 ,如果想在此类中定义,则只能声明为 __declspec(dllexport) int Add(int a, int b);
    在函数定义时,
    __declspec(dllexport) int CExportDll::Add(int a, int b){return a + b;}
    【问题解决】
    extern “C” 不能出现在class CExportDLL 类内是因为:
    动态链接库中的类中的非静态成员函数不允许用extern "C"阻止名字改编。
    类的成员函数是属于类的一部分,不能脱离开类单独存在,而用 extern说明是一个外部成员函数,所以在类中不能用 extern “C” 。
    如果想导出一个类 可以用:宏定义 AFX_EXT_CLASS来代替 __declspec(dllexport) 可以用来修饰 类
    #define AFX_CLASS_EXPORT __declspec(dllexport)
    #define AFX_EXT_CLASS AFX_CLASS_EXPORT
    例如: class AFX_EXT_CLASS DLLExport{};
    或者 class extern “C” __declspec(dllexport) DLLExport{};
    DLLExport为类 前面是导出修饰。
    5)导出函数名称:使用 vc6.0中 depends工具查找 dll所在文件,
    ① __declspec(dllexport) int Add(int a, int b)的导出函数为
    ?Add@@YAHHH@Z
    ② __declspec(dllexport) int __stdcall Add(int a, int b)的导出函数为
    ?Add@@YGHHH@Z
    ③ __declspec(dllexport) int __cdecl Add(int a, int b);的导出函数为
    ?Add@@YAHHH@Z
    extern “C” __declspec(dllexport) int Add(int a, int b)导出函数
    Add
    ⑤ extern “C” __declspec(dllexport) int __stdcall Add(int a, int b)导出函数
    _Add@8
    extern “C” __declspec(dllexport) int __cdecl Add(int a, int b)的导出函数为
    Add
    所以,extern “C” 防止C++名字改编,而 __stdcall 用于Win32API函数约定,使输出函数的前面加一个下划线,函数名称后面加@和参数的字节数,_函数名称@字节数;C/MFC语言默认是__cdecl,导出函数与前者差不多,只是形参列表开始标记由YG编程YA了;

__stdcall 函数调用约定: _函数名@字节数
__cdecl函数调用约定: _函数名@字节数
__fastcall :函数名前后加@,最后加字节数: @函数名@字节数

为了建立自己的标准动态库,建议使用WinAPI 也就是__stdcall约定,这样即使VB调用是也是没问题的。

结论】最后发现用extern “C” 加调用约定用__cdecl输出的函数名称不会改变;extern “C” 加调不用约定时输出的函数名称不会改变;在不使用 extern "C"时,只使用函数调用约定时,输出函数名字也会改编。最后两者要结合使用!!!!
因为__cdecl为C语言默认的,在加入 extern "C"时,有没有此约定都是可以的。
加入__stdcall约定的导出函数可以被其他语言使用,注意,应该是静态调用,不是动态调用(LoadLibrary)但,我测试的时候用的隐式调用,
extern “C” __declspec(dllexport) int __stdcall Add(int a, int b)时
__stdcall约定会报错:无法定位程序输入点Add位于动态连接上。!!!,但他们都建议使用此约定呢???

【问题解决】
无法定位程序输入点Add位于动态连接上是 因为DLL创建使用了Release模式下,而调用时使用的Debug模式下,所以问出现问题,更改后依然会报错error LNK2001: unresolved external symbol _Add
因为DLL创建时使用__stdcall约定,而C++默认为__cdecl,所以会报错。
修改约定:属性-》C/C++中 -》category》code generation》_calling convention 中__cdecl 修改为__stdcal就可以啦
所以,此问题是可以。
【还有一种error情况】当修改带__stdcal的头文件时,DLL的工程必须是release模式下编译,否则在调用时会报 unresolved external symbol _Add@8。(是不是VC6.0的bug?)
【结论】动态调用时只有下式成功了,隐式调用时这个也可以,就按照下式写就可以!
extern “C” __declspec(dllexport) int Add(int a, int b)

方法二:添加def文件
1)Win32项目中没有.def文件,先在工程目录下创建一个记事本,更改名称为工程名字,且后缀修改为.def
2)DLL工程中,添加 新文件,就可以啦。VC6.0中直接添加def文件就可以,不用修改属性什么的。
实例如下:
; CreateWin32DLL.def : Declares the module parameters for the DLL.

LIBRARY “CreateWin32DLL”
DESCRIPTION ‘CreateWin32DLL Windows Dynamic Link Library’

EXPORTS
; Explicit exports can go here

Add @1
Subtract @2

结论:
为了解决输出函数名称被修改问题,有两种方法
(一) 添加 extern “C” 不添加其他 函数调用约定:
extern “C” __declspec(dllexport) int Add(int a, int b);
(二)添加.def文件,这样既能确保函数名称不变,而且还能保证动态链接库的入口点函数名字不变。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值