VS创建和使用Cpp动态链接库教程

⌚Time: 2022-03-19 19:31:40

👨‍💻Author: Jack Ge

环境

系统:windows10

IDE:vs2005


创建

1.创建项目

打开vs,文件,新建项目,win32控制台应用程序,为项目起名

点击下一步,选择应用程序类型,dll,附加选项,空项目,点击完成

2.编辑代码

用于测试的库包括一个函数一个类,函数实现计算阶乘的功能,类里包含打印爱心形状功能的成员函数。

对头文件夹右键点击,添加,新建项,选择头文件

Microsoft 专用

dllexport 和 dllimport 存储类特性是 C 和 C++ 语言的 Microsoft 专用扩展。 可以使用它们从 DLL 中导出或向其中导入函数、数据和对象。

语法


__declspec( dllimport ) declarator

__declspec( dllexport ) declarator

dllexport是在这些类、函数以及数据的申明的时候使用。用他表明这些东西可以被外部函数使用,即(dllexport)是把 DLL中的相关代码(类,函数,数据)暴露出来为其他应用程序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。

dllimport是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL 内部代码(类,函数,全局变量)时,只需要在程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。

_declspec(dllexport)与_declspec(dllimport)是相互呼应,只有在DLL内部用dllexport作了声明,才能在外部函数中用dllimport导入相关代码。

对于动态链接库,类和函数的格式:

导出函数


__declspec(dllexport) 返回值 函数名(参数列表);

导出类


class __declspec(dllexport) 类名;

在使用时,使用


__declspec(dllimport) declarator;

编辑头文件,对函数和类进行声明


#pragma once

#ifdef LIBSASA_EXPORTS

#define LIBSASA_API __declspec(dllexport)

#else

#define LIBSASA_API __declspec(dllimport)

#endif

LIBSASA_API void print_l();

class LIBSASA_API CCC{

public:

    CCC(char *,int);

    void intro_self();

private:

    char name[1024];

    int age;

};

DLL 项目的新项目模板会将 PROJECTNAME_EXPORTS 添加到定义预处理器宏。 在此示例中,Visual Studio 在生成 libsasa DLL 项目时定义 LIBSASA_EXPORTS。

定义 LIBSASA_EXPORTS宏时,LIBSASA_API 宏会对函数声明设置 __declspec(dllexport) 修饰符。 此修饰符指示编译器和链接器从 DLL 导出函数或变量,以便其他应用程序可以使用它。 如果未定义 LIBSASA_EXPORTS(例如,当客户端应用程序包含头文件时),LIBSASA_API 会将 __declspec(dllimport) 修饰符应用于声明。 此修饰符可优化应用程序中函数或变量的导入

在源文件夹,添加一个cpp文件,实现所需的功能


#include"sasa.h"

#include "sasa.h"

#include <iostream>

#include <stdlib.h>

#include <string.h>

using namespace std;

void print_love(){

    float y,x,a;

    for(y=1.5f; y>-1.5f; y-=0.1f){

        for (x=-1.5f; x<1.5f; x+=0.05f){

            a = x*x + y*y - 1;

            putchar(a*a*a - x*x*y*y*y <= 0.0f? '*':' ');

        }

        putchar('\n');

    }

}

CCC::CCC(char *n,int a){

    memset(name, 0, sizeof(name));

    strcpy(name, n);

    age = a;

}

void CCC::intro_self(){

    cout<<"I am a "<<age<<" year old person and my name is "<<name<<endl;

}

在菜单栏上选择生成>生成解决方案

DLL 和相关编译器输出放在解决方案文件夹正下方的“Debug”文件夹中 。 如果创建发布版本,该输出会放置在“Release”文件夹中

打开项目文件夹下的debug目录

会发现已经生成了相应的动态库文件libsasa.dll

同时又生成了一个.lib文件。对于.lib文件,通常是windows静态链接库文件。

实际上,这里的.lib文件不是静态链接库文件。这个.lib文件里有相应的.dll文件的名字和一个指明.dll文件中函数入口的顺序表。使用动态库编译程序时会使用到。因此,动态库的dll文件,伴随的lib文件和相关的头文件是一起发行的


使用

在msvc中,对于动态库的使用,有两种方法,一种方法是动态加载,在程序运行过程中,使用LoadLibrary()、GetProcessAddress()和FreeLibrary()三个函数动态的对动态库进行加载和卸载,此方法在编译运行时只需要dll文件的支持即可

另一种方法是静态加载,静态加载不仅需要dll文件,在程序编译时也需要dll文件对应的lib文件,这个lib文件会记录动态库名称与函数入口,使程序开始运行时能够正确的对动态库文件进行载入并使用。

下面使用静态加载的办法

1.创建项目

另外启动vs。新建一个项目

点击完成

在项目目录新建include和lib两个文件夹,将libsasa库的头文件和lib文件分别放进去

对头文件文件夹右键,添加,现有项,选择动态库头文件,添加include文件夹下的头文件

点击项目,属性,链接器,常规,附加库目录。将libabc项目生成的lib文件所在的目录添加进去

点击输入,附加依赖项,添加生成的lib文件名称

2.代码

对源文件文件夹右键,添加,新建项,创建一个cpp源文件

编辑源文件,调用动态库中相关功能

main.cpp


#include"include/sasa.h"

#include<windows.h>

#include<iostream>

int main(){



    print_l();

    CCC c("sks",55);

    c.intro_self();

    system("pause");

    return 0;

}

点击启动调试,生成程序,之后会发现无法运行,因为系统找不到动态库libabc.dll

将动态库libsasa.dll拷贝到此文件夹下(系统会从程序运行目录下搜索动态库文件)

之后再次运行程序

为了使程序实现C++代码调用C语言代码,使用extern "C"进行修饰符号,因此动态库头文件的形式是


#pragma once

#ifdef LIBSASA_EXPORTS

#define LIBSASA_API __declspec(dllexport)

#else

#define LIBSASA_API __declspec(dllimport)

#endif

#ifdef __cplusplus

extern "C" {

#endif

LIBSASA_API void print_l();

class LIBSASA_API CCC{

public:

    CCC(char *,int);

    void intro_self();

private:

    char name[1024];

    int age;

};



#ifdef __cplusplus

}

#endif