分享

C/C /C#使用C/C 动态链接库DLL 错误现象及解决办法 图文详解

 老来乐65 2019-09-28

目录

MFC应用程序使用DLL

Step#1 创建MFC应用程序,名称TestDll,基于对话框的,最后点击Finish

Step#2 添加两个按钮Add和Subtract

Step#3双击Add按钮添加命令响应函数

Step#4添加代码

Step#5错误及解决办法

第一个错误 error C2664 cannot convert argument 1 from 'const char [7]' to 'const wchar_t *'

第二个错误 error MSB8031: Building an MFC project for a non-Unicode character set is deprecated.

第三个错误 error LNK2019: unresolved external symbol

第四个错误error LNK1104: cannot open file 'MyDll0.lib' 

第五个错误 error LNK2019: unresolved external symbol __imp__add referenced in function 

第六个错误 找不到MyDll0.dll,无法继续执行代码。重新安装程序可能会解决此问题

Step#6程序运行结果

Step#4添加代码之第二种方法【推荐使用此种,实际工程中应用的比较多】

TestDllDlg.cpp代码

错误及解决办法error LNK2019: unresolved external symbol _add referenced in function

汇总C/C++使用 DLL步骤

C#应用程序使用DLL

Step#1. 新建C#项目,Windows Forms Application,取名CSharpTestDll

Step#2 添加两个按钮Add和Subtract

​Step#3双击Add按钮添加事件响应函数,Subtract按钮也要双击

Step#4. 将被使用到的MyDll0.dll放置在'项目的Output Path'目录下。

Step#5添加代码

Form1.cs完整版代码如下

Step#6错误及解决办法

Step#7 Build成功&运行

辅助工具

Dumpbin

Dependency Walker



MFC应用程序使用DLL

Step#1 创建MFC应用程序,名称TestDll,基于对话框的,最后点击Finish

Step#2 添加两个按钮Add和Subtract

这里使用的dll为《创建动态链接库(dll)》中创建的MyDll0.dll

ID Caption 命令响应函数 函数功能
IDC_BTN_ADD Add OnBnClickedBtnAdd 调用MyDll0.dll的add函数
IDC_BTN_SUBTRACT Subtract OnBnClickedBtnSubtract 调用MyDll0.dll的subtract函数

Step#3双击Add按钮添加命令响应函数

Step#4添加代码

  1. extern 'C' _declspec(dllimport) int _stdcall add(int a, int b);
  2. extern 'C' _declspec(dllimport) int _stdcall subtract(int a, int b);
  3. void CTestDllDlg::OnBnClickedBtnAdd()
  4. {
  5. // TODO: Add your control notification handler code here
  6. CString str;
  7. str.Format('5+3=%d', add(5, 3));
  8. MessageBox(str);
  9. }
  10. void CTestDllDlg::OnBnClickedBtnSubtract()
  11. {
  12. // TODO: Add your control notification handler code here
  13. CString str;
  14. str.Format('5-3=%d', subtract(5, 3));
  15. MessageBox(str);
  16. }

Step#5错误及解决办法

第一个错误 error C2664 cannot convert argument 1 from 'const char [7]' to 'const wchar_t *'

错误说明:error C2664: 'void ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Format(UINT,...)' : cannot convert argument 1 from 'const char [7]' to 'const wchar_t *'
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

解决办法:VS2013默认使用UNICODE编码,将其修改为Not Set

Project -> Properties -> Configuration Properties -> General -> Character Set: Not Set

第二个错误 error MSB8031: Building an MFC project for a non-Unicode character set is deprecated.

错误说明:error MSB8031: Building an MFC project for a non-Unicode character set is deprecated. You must change the project property to Unicode or download an additional library. See http://go.microsoft.com/fwlink/p/?LinkId=286820 for more information.

解决办法:
VS2013把 multi-byte character set 支持移除了

去微软网站下载这个组件就行了,网址http://go.microsoft.com/fwlink/p/?LinkId=286820

Multibyte MFC Library for Visual Studio 2013

【注意】根据自己的VS版本来选择组件,笔者的是VS2013

参考文章https://blog.csdn.net/tahelin/article/details/30312881

第三个错误 error LNK2019: unresolved external symbol

错误说明:error LNK2019: unresolved external symbol __imp__add@8 referenced in function 'public: void __thiscall CTestDllDlg::OnBnClickedBtnAdd(void)' (?OnBnClickedBtnAdd@CTestDllDlg@@QAEXXZ)

error LNK2019: unresolved external symbol 'int __cdecl add(int,int)' (?add@@YAHHH@Z) referenced in function 'public: void __thiscall CTestDllDlg::OnBnClickedBtnAdd(void)' (?OnBnClickedBtnAdd@CTestDllDlg@@QAEXXZ) 

 error LNK2019: unresolved external symbol 'int __cdecl subtract(int,int)' (?subtract@@YAHHH@Z) referenced in function 'public: void __thiscall CTestDllDlg::OnBnClickedBtnSubtract(void)' (?OnBnClickedBtnSubtract@CTestDllDlg@@QAEXXZ)   

 error LNK1120: 2 unresolved externals 

解决办法:这几个错误是链接(Link)时发生的,因为链接器需要知道这两个函数在哪个地方实现的,所以报错。

1. 将MyDll0.lib放置在TestDll.exe生成目录中,笔者的项目中为Debug目录,如下图

2. 按照下图添加Additional Dependecies附加依赖项

第四个错误error LNK1104: cannot open file 'MyDll0.lib' 

解决办法:

这是因为没有告诉链接器(LINK)去哪里找这个MyDll0.lib

VC++ Directories -> Library Directories(附加库目录)

填入MyDll0.lib所在的目录

绝对路径F:\Code\VS_C++\TestDll\Debug

相对路径..\Debug【两个点代表上层目录】

在笔者的项目中,当前目录是TestDll.sln所在的目录

至此已经可以Build&Link成功,并生成了TestDll.exe,如下图:

第五个错误 error LNK2019: unresolved external symbol __imp__add referenced in function 

错误说明:error LNK2019: unresolved external symbol __imp__add referenced in function 'public: void __thiscall CTestDllDlg::OnBnClickedBtnAdd(void)' (?OnBnClickedBtnAdd@CTestDllDlg@@QAEXXZ)

【重点】解决办法:要看导出函数声明与导入函数声明是否一致

本例中,查看MyDll0.h中的函数声明是否与使用者TestDllDlg.cpp中的函数声明是否一致

错误例子:

MyDll0.h中的声明为

extern 'C' _declspec(dllexport) int   _stdcall add(int a, int b);

TestDllDlg.cpp中的声明为

extern 'C' _declspec(dllimport) int   add(int a, int b);【缺少_stdcall,所以错误】

正确例子:

MyDll0.h中的声明为

extern 'C' _declspec(dllexport) int   _stdcall add(int a, int b);

TestDllDlg.cpp中的声明为

extern 'C' _declspec(dllimport) int   _stdcall add(int a, int b);

第六个错误 找不到MyDll0.dll,无法继续执行代码。重新安装程序可能会解决此问题

解决办法:将MyDll0.dll放置在TestDll.exe的同层目录下(最终打包给别人的就是这样的目录结构),如下图:

Step#6程序运行结果

Step#4添加代码之第二种方法【推荐使用此种,实际工程中应用的比较多】

TestDllDlg.cpp代码

只需要加上一句#include 'MyDll0.h'

  1. #include 'MyDll0.h'
  2. void CTestDllDlg::OnBnClickedBtnAdd()
  3. {
  4. // TODO: Add your control notification handler code here
  5. CString str;
  6. str.Format('5+3=%d', add(5, 3));
  7. MessageBox(str);
  8. }
  9. void CTestDllDlg::OnBnClickedBtnSubtract()
  10. {
  11. // TODO: Add your control notification handler code here
  12. CString str;
  13. str.Format('5-3=%d', subtract(5, 3));
  14. MessageBox(str);
  15. }

MyDll0.h代码

具体可以参考《创建动态链接库(dll)》

  1. #pragma once
  2. #ifndef _MYDLL_API
  3. #define _MYDLL_API extern 'C' _declspec(dllexport)
  4. #else
  5. #define _MYDLL_API _declspec(dllimport)
  6. #endif
  7. _MYDLL_API int _stdcall add(int a, int b);
  8. _MYDLL_API int _stdcall subtract(int a, int b);

错误及解决办法error LNK2019: unresolved external symbol _add referenced in function

错误说明:error LNK2019: unresolved external symbol _add referenced in function 'public: void __thiscall CTestDllDlg::OnBnClickedBtnAdd(void)' (?OnBnClickedBtnAdd@CTestDllDlg@@QAEXXZ)   

解决办法:先把用到的头文件复制到调用者的目录下,然后配置包含目录

1. 复制MyDll0.h到TestDll.h/TestDll.cpp, TestDllDlg.h/TestDllDlg.cpp同层目录下

2. 配置包含目录:VC++ Directories -> Include Directories(包含目录)

不会用相对路径的朋友就填绝对路径:F:\Code\VS_C++\TestDll\TestDll

相对路径..\TestDll【两个点代表上层目录】

在笔者的项目中,当前目录是TestDll.sln所在的目录

汇总C/C++使用 DLL步骤

1. 导入函数声明

Dll的使用者(调用者、客户端)需要将导入函数声明为extern或_declspec(dllimport)

并配置包含目录:VC++ Directories -> Include Directories(包含目录)【头文件目录】

【建议使用相对路径】

2. 添加库文件:

将MyDll.lib放置在TestDll.exe的同层目录下【建议使用相对路径】

并配置附加库目录:VC++ Directories -> Library Directories(附加库目录)

3. 将被用到的.dll放置在使用者(.exe)能找到的目录下

可以参考文章《动态链接库加载的两种方式》中的“四大路径及顺序

【注意事项】如果xxx.dll有任何更新(xxx.h/xxx.cpp),需要将更新&build后的xxx.h/xxx.lib/xxx.dll提供给使用者(客户端)。

C#应用程序使用DLL

与C/C++使用DLL相比要方便多。

Step#1. 新建C#项目,Windows Forms Application,取名CSharpTestDll

Step#2 添加两个按钮Add和Subtract


Step#3双击Add按钮添加事件响应函数,Subtract按钮也要双击

Step#4. 将被使用到的MyDll0.dll放置在'项目的Output Path'目录下。

建议去使用者(客户端)项目属性中去查看,保持一致才不会出错。

【注意】需要查看这几个红色框出的位置,如下图

项目的Output Path(输出目录)

项目名称 -> 右击 -> 属性Properties

Step#5添加代码

1. 在Form1.cs中添加一行代码

using System.Runtime.InteropServices;   //DLL support

2. 在添加如下代码来声明add与subtract函数是外部函数

  1. [DllImport('MyDll0.dll')] // 注意.dll路径要能被找到
  2. public static extern int add(int a, int b); // 被调用的函数需要被声明为static与extern
  3. [DllImport('MyDll0.dll')] // 注意.dll路径要能被找到
  4. public static extern int subtract(int a, int b); // 被调用的函数需要被声明为static与extern

3. 在btn_add_Click与btn_Subtract_Click函数中添加如下代码

  1. private void btn_add_Click(object sender, EventArgs e)
  2. {
  3. string str = '3 + 5 = ' + add(3, 5).ToString();
  4. MessageBox.Show(str, '提示');
  5. }
  6. private void btn_Subtract_Click(object sender, EventArgs e)
  7. {
  8. string str = '3 - 5 = ' + subtract(3, 5).ToString();
  9. MessageBox.Show(str, '提示');
  10. }

Form1.cs完整版代码如下

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. using System.Runtime.InteropServices; //DLL support
  11. namespace CSharpTestDll
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. }
  19. [DllImport('MyDll0.dll')] // 注意.dll路径要能被找到
  20. public static extern int add(int a, int b); // 被调用的函数需要被声明为static与extern
  21. [DllImport('MyDll0.dll')] // 注意.dll路径要能被找到
  22. public static extern int subtract(int a, int b); // 被调用的函数需要被声明为static与extern
  23. private void btn_add_Click(object sender, EventArgs e)
  24. {
  25. string str = '3 + 5 = ' + add(3, 5).ToString();
  26. MessageBox.Show(str, '提示');
  27. }
  28. private void btn_subtract_Click(object sender, EventArgs e)
  29. {
  30. string str = '3 + 5 = ' + subtract(3, 5).ToString();
  31. MessageBox.Show(str, '提示');
  32. }
  33. }
  34. }

Step#6错误及解决办法

常见错误:无法加载“MyDll0.dll”:找不到指定的模块

解决办法:将被使用到的MyDll0.dll放置在.exe同层目录下。

Step#7 Build成功&运行

辅助工具

Dumpbin

dumpbin -exports MyDll0.dll【推荐使用,速度快】

参考文章《如何查看动态链接库dll导出哪些函数》

Dependency Walker

下载地址http://www./

更多实用工具请参考《软件开发者的常用工具》

更多内容请看C/C++动态链接库(DLL)详解

来源:孙鑫_VC++_学习笔记

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多