zoukankan      html  css  js  c++  java
  • Window中创建和使用静态库与动态库

    一、静态库的创建和使用

    1. 静态库的创建

    (1) 在VS2013中选择菜单->File->New->Project,选择Visual C++ ->Win32选项,然后点击Win32 Project图标,选择Win32 Application Wizard,选择Application type下的Static library选项。工程名字为TestStaticLib。

    (2)在Solution Explorer的Header Files下新建一个test_header.h头文件

     1 #ifndef TEST_HEADER_H_
     2 #define TEST_HEADER_H_
     3 
     4 #ifdef _WIN32
     5 #ifdef _LIB
     6 #define DECLSPEC __declspec(dllexport)
     7 #else
     8 #define DECLSPEC __declspec(dllimport)
     9 #endif
    10 #else
    11 #define DECLSPEC
    12 #endif
    13 
    14 #endif

    __declspec修饰符仅在Windows平台下有效。
    __declspec(dllexport)的作用是将当前函数或者类导出,以便可以从DLL中调用。

    __declspec(dllimport)的作用是在应用程序中可以使用导出的DLL函数或者类。

    在VS2013编译器中新建一个Static library工程的时候,预定义了_LIB宏,所以上面的代码中

    #define DECLSPEC __declspec(dllexport)是有效的。

    (3) 在Solution Explorer的Header Files下新建一个Source.h文件

     1 #ifndef SOURCE_H_
     2 #define SOURCE_H_
     3 #include "test_header.h"
     4 
     5 DECLSPEC int MyFunction(int a,int b);
     6 
     7 class DECLSPEC MyClass
     8 {
     9 public:
    10     MyClass(int a, int b) : m_a(a), m_b(b){}
    11     ~MyClass();
    12     int add();
    13 private:
    14     int m_a;
    15     int m_b;
    16 };
    17 #endif

    (4) 在Solution Explorer的Source Files文件夹下新建一个Source.cpp文件

     1 #include "Source.h"
     2 
     3 int  MyFunction(int a,int b)
     4 {
     5     return a + b;
     6 }
     7 
     8 MyClass::~MyClass()
     9 {
    10 }
    11 
    12 int MyClass::add()
    13 {
    14     return m_a + m_b;
    15 }

    (5) 编译工程,在工程目录的Debug文件夹下会生成TetsStaticLib.lib静态库文件。
    2. 静态库的使用

    新建一个Win32 Console工程,名字为TestLib。

    设置TestLib的工程属性

    ①Configuration Properties->C/C++->General->Additional Include Directories

    D:ProgramC++ProTestStaticLibTestStaticLib

    ②Configuration Properties->Linker->General->Additional Library Directories

    D:ProgramC++ProTestStaticLibDebug

    ③Configuration Properties->Linker->Input->Additional Dependencies

    TestStaticLib.lib

    添加如下测试代码

     1 #include "stdafx.h"
     2 #include "Source.h"
     3 #include <iostream>
     4 using namespace std;
     5 
     6 
     7 int _tmain(int argc, _TCHAR* argv[])
     8 {
     9     int c = MyFunction(1, 2);
    10     cout << c << endl;
    11 
    12     MyClass cla(2, 4);
    13     cout << cla.add() << endl;
    14     system("pause");
    15     return 0;
    16 }

     编译运行生成的TestLib.exe,可以看到程序结果,这时将TestLib.exe拷贝到任意文件夹也可以运行。

     二、动态库的创建和使用

    1. 动态库的创建

    (1) 在VS2013中选择菜单->File->New->Project,选择Visual C++ ->Win32选项,然后点击Win32 Project图标,选择Win32 Application Wizard,选择Application type下的DLL选项。工程名字为TestDLL。

    (2)在Solution Explorer的Header Files下新建一个test_header.h头文件

     1 #ifndef TEST_HEADER_H_
     2 #define TEST_HEADER_H_
     3 
     4 #ifdef _WIN32
     5 #ifdef TESTDLL_EXPORTS
     6 #define DECLSPEC __declspec(dllexport)
     7 #else
     8 #define DECLSPEC __declspec(dllimport)
     9 #endif
    10 #else
    11 #define DECLSPEC
    12 #endif
    13 
    14 #endif

    (3)在Solution Explorer的Header Files下新建一个Source.h文件

     1 #ifndef SOURCE_H_
     2 #define SOURCE_H_
     3 #include "test_header.h"
     4 
     5 DECLSPEC int MyFunction(int a,int b);
     6 
     7 class DECLSPEC MyClass
     8 {
     9 public:
    10     MyClass(int a, int b) : m_a(a), m_b(b){}
    11     ~MyClass();
    12     int add();
    13 private:
    14     int m_a;
    15     int m_b;
    16 };
    17 #endif

    (4) 在Solution Explorer的Source Files文件夹下新建一个Source.cpp文件

     1 #include "stdafx.h"
     2 #include "Source.h"
     3 
     4 int  MyFunction(int a,int b)
     5 {
     6     return a + b;
     7 }
     8 
     9 MyClass::~MyClass()
    10 {
    11 }
    12 
    13 int MyClass::add()
    14 {
    15     return m_a + m_b;
    16 }

    (5) 编译工程,在工程目录的Debug文件夹下会生成TestDLL.dll动态链接文件以及它的导出符号文件TestDLL.lib。
    2. 动态库的使用

    (1) 隐式使用

    新建一个Win32 Console工程,名字为TestLib。

    设置TestLib的工程属性

    ①Configuration Properties->C/C++->General->Additional Include Directories

    D:ProgramC++ProTestStaticLibTestDLL

    ②Configuration Properties->Linker->General->Additional Library Directories

    D:ProgramC++ProTestStaticLibDebug

    ③Configuration Properties->Linker->Input->Additional Dependencies

    TestDLL.lib

    添加如下测试代码

     1 #include "stdafx.h"
     2 #include "Source.h"
     3 #include <iostream>
     4 using namespace std;
     5 
     6 
     7 int _tmain(int argc, _TCHAR* argv[])
     8 {
     9     int c = MyFunction(1, 2);
    10     cout << c << endl;
    11 
    12     MyClass cla(2, 4);
    13     cout << cla.add() << endl;
    14     system("pause");
    15     return 0;
    16 }

     编译运行生成的TestLib.exe,可以看到程序结果,注意TestLib.exe必须与TestDLL.dll同一目录才可以运行。

    (2) 显示使用(该方法不能使用导出的类)

    修改Source.h

    1 #ifndef SOURCE_H_
    2 #define SOURCE_H_
    3 #include "test_header.h"
    4 
    5 extern "C" DECLSPEC int MyFunction(int a, int b);
    6 
    7 #endif

    重新编译TestDLL工程
    添加如下测试代码:

     1 #include "stdafx.h"
     2 #include <Windows.h>
     3 #include <iostream>
     4 using namespace std;
     5 
     6 
     7 int _tmain(int argc, _TCHAR* argv[])
     8 {
     9     typedef int (*MyFunctionSame)(int a, int b);
    10 
    11     HINSTANCE handle = LoadLibrary(L"TestDLL.dll");
    12     if (!handle)
    13     {
    14         cout << "Cannot load plugin!" << endl;
    15         exit(1);
    16     }
    17     MyFunctionSame fptr = (MyFunctionSame)GetProcAddress(handle, "MyFunction");
    18     if (fptr == (MyFunctionSame)NULL)
    19     {
    20         cout << "Cannnot find function in plugin: " << endl;
    21         FreeLibrary(handle);
    22         exit(1);
    23     }
    24     
    25     cout << fptr(1, 2) << endl;
    26     FreeLibrary(handle);
    27 
    28     system("pause");
    29     return 0;
    30 }

    显示加载的好处是不许要.lib导入库文件以及.h头文件。但是缺点是只能导出函数。另外,在导出函数的前面必须加extern "C"。
    extern "C"的作用是强制使用C语言的函数命名规则,可以使用下面的命令查看当前DLL下的导出函数表。

     DUMPBIN /EXPORTS TestDLL.dll

     3.关于.def文件

    除了使用__declspec声明修改源文件外,还可以使用模块定义文件(.def文件)

    修改TestDLL工程中的Source.h文件如下:

    1 #ifndef SOURCE_H_
    2 #define SOURCE_H_
    3 #include "test_header.h"
    4 
    5 int __stdcall MyFunction(int a, int b);
    6 
    7 #endif

    新建一个Source.def文件

    1 LIBRARY "TestDLL"
    2 EXPORTS
    3     MyFunction @1

    注意上面的@1就是DLL文件中的导出序号,可以通过DUMPBIN命令查看DLL文件。
    设置TestDLL的工程属性

    Configuration Properties->Linker->Input->Module Definition File

    Source.def

    重新编译TestDLL工程,这样生成的TestDLL.dll文件自带导出符号信息。

    新建一个Win32 Console工程,测试TestDLL.dll文件

     1 #include <Windows.h>
     2 #include <iostream>
     3 using namespace std;
     4 
     5 
     6 int _tmain(int argc, _TCHAR* argv[])
     7 {
     8     typedef int(__stdcall *MyFunctionSame)(int a, int b);
     9 
    10     HINSTANCE handle = LoadLibrary(L"TestDLL.dll");
    11     if (!handle)
    12     {
    13         cout << "Cannot load plugin!" << endl;
    14         exit(1);
    15     }
    16     MyFunctionSame fptr = (MyFunctionSame)GetProcAddress(handle, "MyFunction");
    17     if (fptr == (MyFunctionSame)NULL)
    18     {
    19         cout << "Cannnot find function in plugin: " << endl;
    20         FreeLibrary(handle);
    21         exit(1);
    22     }
    23     
    24     cout << fptr(1, 2) << endl;
    25     FreeLibrary(handle);
    26 
    27     system("pause");
    28     return 0;
    29 }

     4.关于调用约定_stdcall与_cdecl

    _stdcall:参数按从右向左的顺序入栈,由被调用函数清理堆栈.
    _cdecl :参数按从右向左的顺序入栈,由调用函数清理堆栈.

    一般来说,C++使用的是__cdecl调用约定,C#,JAVA等编程语言则是__stdcall,默认情况下使用的是__cdecl方式,

    所以说,如果用c++写的DLL文件想被其它语言调用,必须使用__stdcall方式。

    如果使用__stdcall方式,那么

    即使在函数前加extern "C",导出的函数名也会有变化,例如:

    extern "C" DECLSPEC int  _stdcall  MyFunction(int a, int b);

    通过DUMPBIN工具查看函数名为"MyFunction@8",@8的意思是该函数占用的字节数。

    如果我们使用静态库或者动态库的隐式调用方式,一点影响都没有。

    如果使用动态库的显示调用方式,则无法找到MyFunction函数。

    所以在这种情况下,一定要使用.def的方式去修改导出函数名。参见上面第3条。

  • 相关阅读:
    Maven项目打包时指定配置策略
    使Jackson和Mybatis支持JSR310标准
    Java 8的Time包常用API
    MySQL 聚集拼接
    将List<E>内对象按照某个字段排序
    判断List<E>内是否有重复对象
    eclipse中Maven项目启动报错“3 字节的 UTF-8 序列的字节 3 无效。”
    控制层@Value注解取不到值
    IntelliJ IDEA实时代码模板
    OD: Exploit Me
  • 原文地址:https://www.cnblogs.com/elitiwin/p/4298994.html
Copyright © 2011-2022 走看看