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

8 篇文章 0 订阅
4 篇文章 0 订阅

目录

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

IDCaption命令响应函数函数功能
IDC_BTN_ADDAddOnBnClickedBtnAdd调用MyDll0.dll的add函数
IDC_BTN_SUBTRACTSubtractOnBnClickedBtnSubtract调用MyDll0.dll的subtract函数

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

Step#4添加代码

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

void CTestDllDlg::OnBnClickedBtnAdd()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format("5+3=%d", add(5, 3));
    MessageBox(str);
}


void CTestDllDlg::OnBnClickedBtnSubtract()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format("5-3=%d", subtract(5, 3));
    MessageBox(str);
}

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"

#include "MyDll0.h"

void CTestDllDlg::OnBnClickedBtnAdd()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format("5+3=%d", add(5, 3));
    MessageBox(str);
}


void CTestDllDlg::OnBnClickedBtnSubtract()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format("5-3=%d", subtract(5, 3));
    MessageBox(str);
}

MyDll0.h代码

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

#pragma once
#ifndef _MYDLL_API 
#define _MYDLL_API  extern "C" _declspec(dllexport)
#else
#define _MYDLL_API _declspec(dllimport)
#endif

_MYDLL_API int   _stdcall add(int a, int b);
_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函数是外部函数

一般格式如下

[DLLImport(“DLL文件路径”)]
修饰符 extern 返回值类型 方法名称(参数列表)  

DLLImport会按照顺序去查找DLL文件(程序当前目录>System32目录>环境变量Path所设置路径)。

【注意】

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

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

2. 导出几个函数,就要写几个[DLLImport(“DLL文件路径”)]

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

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

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

private void btn_add_Click(object sender, EventArgs e)
{
	string str = "3 + 5 = " + add(3, 5).ToString();
	MessageBox.Show(str, "提示");
}

private void btn_Subtract_Click(object sender, EventArgs e)
{
	string str = "3 - 5 = " + subtract(3, 5).ToString();
	MessageBox.Show(str, "提示");
}

Form1.cs完整版代码如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;   //DLL support

namespace CSharpTestDll
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        [DllImport("MyDll0.dll")]   // 注意.dll路径要能被找到
        public static extern int add(int a, int b);         // 被调用的函数需要被声明为static与extern
        [DllImport("MyDll0.dll")]   // 注意.dll路径要能被找到
        public static extern int subtract(int a, int b);     // 被调用的函数需要被声明为static与extern
        private void btn_add_Click(object sender, EventArgs e)
        {
            string str = "3 + 5 = " + add(3, 5).ToString();
            MessageBox.Show(str, "提示");
        }

        private void btn_subtract_Click(object sender, EventArgs e)
        {
            string str = "3 + 5 = " + subtract(3, 5).ToString();
            MessageBox.Show(str, "提示");
        }
    }
}

Step#6错误及解决办法

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

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

Step#7 Build成功&运行

辅助工具

Dumpbin

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

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

Dependency Walker

下载地址http://www.dependencywalker.com/

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

 

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

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

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值