VS中 DLL的创建及函数导出(参考MSDN) - photonCarry

时间:2024-03-11 20:59:02

VS中 DLL的创建及函数导出(参考MSDN)

新建一个DLL工程

  新建 - 项目 - vc++ - win32 - win32控制台应用程序,工程名假设取为 MathFuncsDll

  

向导中选择DLL,取消预编译头

完成。

此时会有dllmain.cpp, MathFuncsDll.cpp 两个cpp文件及生成的 stdafx.h, targetver.h stdafx.cpp, 后面这三个文件其实是没用的,可以删掉,然后把dllmain.cpp 中的#include "stdafx.h"改成#include <windows.h>

给工程添加一个头文件MathFuncsDll.h用来定义我们的函数,现在的工程文件如图:

 

在DLL中函数导出有两种方式,一种是利用__declspec(dllexport)语句声明函数,这样便不需要def文件即可导出函数,比如

extern "C" __declspec(dllexport) double  Add1(double a, double b);

对应的函数定义

__declspec(dllexport) double Add1(double a, double b) {
        return a + b;
    }

这里extern "C" 是为了在DLL中生成的函数名不会变化,如果不用该句,Add1在DLL中的导出函数里可能是叫做Add1@SANNN@之类之类的,不方便动态调用(LoadLibrary,GetProcAddress)。

通过denpency walker可以看DLL的导出函数及其名称,这里显示的名称就是GetProcAddress()函数需要的名称,如果名称不对将获取不了函数

  

另一种方法是利用def文件,这种方法得到的导出函数名称更好看,适合动态调用。此时函数的定义就可以写的比较简单了

double Divide2(double a, double b);

double Divide2(double a, double b) {
    if (b == 0)
        throw invalid_argument("b cannot be zero!");
    return a / b;
}

在工程中插入def文件,按下面代码编写

LIBRARY    MathFuncsDll
EXPORTS
    Divide2 @1

第一行是LIBRARY关键字,后接库名称

第二行是EXPORTS关键字

再往下就是要导出的函数名及其序号。

 

附上代码:

// MathFuncsDll.cpp : 定义 DLL 应用程序的导出函数。
//

#include "MathFuncsDll.h"
#include <stdexcept>

using namespace std;

namespace MathFuncs {
    double MyMathFuncs::Add(double a, double b) {
        return a + b;
    }
    
    double MyMathFuncs::Subtract(double a, double b) {
        return a - b;
    }
    
    double MyMathFuncs::Multiply(double a, double b) {
        return a * b;
    }
    
    double MyMathFuncs::Divide(double a, double b) {
        if (b == 0)
            throw invalid_argument("b cannot be zero!");
        return a / b;
    }
}
MATHFUNCSDLL_API double Add1(double a, double b) {
        return a + b;
    }

MATHFUNCSDLL_API double Subtract1(double a, double b) {
        return a - b;
    }

MATHFUNCSDLL_API double Multiply1(double a, double b) {
        return a * b;
    }

MATHFUNCSDLL_API double Divide1(double a, double b) {
        if (b == 0)
            throw invalid_argument("b cannot be zero!");
        return a / b;
}

double Divide2(double a, double b) {
    if (b == 0)
        throw invalid_argument("b cannot be zero!");
    return a / b;
}

头文件:

#pragma once

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif

namespace MathFuncs {
    class MyMathFuncs {
    public:
        static MATHFUNCSDLL_API double Add(double a, double b);
        static MATHFUNCSDLL_API double Subtract(double a, double b);
        static MATHFUNCSDLL_API double Multiply(double a, double b);
        static MATHFUNCSDLL_API double Divide(double a, double b);

    };
}
extern "C" MATHFUNCSDLL_API double  Add1(double a, double b);
extern "C" MATHFUNCSDLL_API double Subtract1(double a, double b);
extern "C" MATHFUNCSDLL_API double Multiply1(double a, double b);
extern "C" MATHFUNCSDLL_API double Divide1(double a, double b);
double Divide2(double a, double b);

这里除了普通的函数,还有在命名空间中的类的静态函数。不过这种函数通过GetProcAddress()将会很难调用,如果是通过链接lib文件来调用则会比较容易,比如

cout << "a + b = " <<
        MathFuncs::MyMathFuncs::Add(a, b) << endl;