• Windows中的库编程


    Windows操作系统中,库分为动态链接库(dll)和静态链接库(lib)

    动态库是Windows中实现代码共享的一种方式。它是一个二进制式文件,不可单独运行,需要调用方调用才能运行。在Windows中,动态库可以被多种编程语言所支持。

    静态链接库不同于动态链接库(dll),在静态库情况下,函数和数据被编译进一个二进制 文件(通常扩展名为*.lib),Visual C++的编译器在链接过程中将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为"静态链接",此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。

    使用动态库有以下好处:

    1、有利于代码和数据的共享

    2、有利于模块化开发

    3、有利于软件升级

    4、代码保护

    动态链接库又分为Win32动态链接库和MFC动态链接库。区别就是是否使用了MFC类

    Win32 DLL编程

     如何导出Win32 DLL

    1、通过关键字_declspec(dllexport导出)

    新建一个C++ dll工程 DllExportTest

    新建一个DllExportTest..h文件

    输入

    1 #pragma once
    2 
    3 __declspec(dllexport) void PrintHelloWorld();

    在DllExportTest.cpp中输入

     1 #include "stdafx.h"
     2 #include"DllExportTest.h"
     3 #include<iostream>
     4 
     5 using namespace std;
     6 
     7 void PrintHelloWorld()
     8 {
     9     cout << "HelloWorld" << endl;
    10 }

    2、通过模块定义文件导出

    新建一个C++ dll工程 DllExportWithDEFTest

    新建一个DllExportWithDEFTest.h,输入

    1 #pragma once
    2 
    3 void PrintHelloWorld();

    在DllExportWithDEFTest.cpp中输入

     1 #include "stdafx.h"
     2 #include"DllExportWithDEFTest.h"
     3 #include<iostream>
     4 
     5 using namespace std;
     6 
     7 void PrintHelloWorld()
     8 {
     9     cout << "HelloWorld" << endl;
    10 }

    然后在“源文件”上右键选择“添加新项”,选择“代码”->”模块定义文件(.def)“

    .def常用格式如下

    LIBRARY   DllName                  //dll名字, DllName可以为空
    DESCRIPTION    DllDescription      //dll 描述 这一行可以省略
    EXPORTS FuncOrVariables             //要导出的函数名或变量的名字

    我在前面的代码中定义了PrintHelloWorld函数,要将它导出,可以这样定义.def文件

    LIBRARY   
    EXPORTS
    PrintHelloWorld

    如果要将PrintHelloWorld函数导出为其它的名字,如MyFuncName,可以这样定义.def文件

    LIBRARY   
    EXPORTS
    MyFuncName = PrintHelloWorld

    如何使用导出的函数

    C#调用可以参考以下链接

    https://www.cnblogs.com/zhaotianff/p/8991847.html

    C++调用

    分为隐式链接和显式链接两种方式

    隐式链接

    步骤如下

    1、引入lib文件

    2、引入头文件

    3、调用dll中的数据

    新建一个C++ 控制台程序 InvokeDll

     

    打开项目的目录,建立lib和include文件夹(这个操作不是必须的,.h和.lib可以通过路径引用,不一定非要建立这样的文件夹,但这样操作会更好管理)

    把前面生成的DllExportTest.lib拷到lib文件夹下,把DllExportTest.h拷到include文件夹下

    然后在项目上单击右键,选择属性,依次选择配置属性-》链接器-》常规-》附加库目录。新建一个路径,选择刚才建立 的lib文件夹,单击确定

    再选择输入-》附加依赖项,增加DllExportTest.lib

    在InvokeDll.cpp中输入以下代码

    1 #include "stdafx.h"
    2 #include "includeDllExportTest.h"
    3 
    4 
    5 int main()
    6 {
    7     PrintHelloWorld();
    8     return 0;
    9 }

    运行之后可以看到屏幕输出HelloWorld

    隐式链接还有一种方式,使用指令#pragma comment来引用lib文件

    新建一个C++控制台程序 InvokeDll_2

    复制InvokeDll项目路径下的include和lib文件夹到InvokeDll_2的项目路径下,在InvokeDll_2.cpp中输入以下代码

     1 #include "stdafx.h"
     2 #include "./include/DllExportTest.h"
     3 
     4 #pragma comment(lib,"./lib/DllExportTest.lib")
     5 
     6 int main()
     7 {
     8     PrintHelloWorld();
     9     return 0;
    10 }

    运行之后也可以看到屏幕输出HelloWorld

     显式链接

    显示链接主要是通过调用LoadLibrary、GetProcAddress、FreeLibrary这三个API函数来实现

    LoadLibrary()

    声明如下

    HMODULE WINAPI LoadLibrary( _In_ LPCTSTR lpFileName);

    用于载入指定的动态链接库

    GetProcAddress()

    声明如下

    FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );

    用于检索指定的动态链接库中函数地址

    FreeLibrary()

    声明如下

    BOOL FreeLibrary( HMODULE hLibModule );

    用于释放指定的动态链接库

    新建一个C++控制台程序 InvokeDllExplicitly,在InvokeDllExplicitly.cpp中输入以下代码

     1 #include "stdafx.h"
     2 #include <Windows.h>
     3 
     4 typedef void(*MyFunc)();  //后面是函数签名部分,需要跟导出函数中的保持一致。这个函数没有参数,所以后面部分为空
     5 
     6 int main()
     7 {
     8     HMODULE hDll = NULL;
     9     MyFunc myFunc = NULL;
    10 
    11     //加载库
    12     hDll= LoadLibrary("./DllExportTest.dll");
    13 
    14     if (hDll)
    15     {
    16         //获取函数或变量的地址
    17         myFunc =(MyFunc)GetProcAddress(hDll, "PrintHelloWorld");
    18 
    19         if (myFunc)
    20         {
    21             //调用函数
    22             myFunc();
    23         }
    24     }
    25 
    26     //释放动态链接库
    27     FreeLibrary(hDll);
    28 
    29     return 0;
    30 }

    运行可以看到屏幕输出 HelloWorld

  • 相关阅读:
    g2o中setparameterid(0,0)方法
    SLAM细碎内容积累_来自各种技术交流群_持续更新
    进程与线程
    写程序要注意的
    SSE优化指令集编译错误: inlining failed in call to always_inline 'xxx': target specific option mismatch xxx
    为一个vector<cv::KeyPoint*> 类型的变量做初始化
    prototype for '类名::函数名'does not match any in class'类名'
    error: field has incomplete type
    error: invalid use of incomplete type
    父类和子类可以相互转化吗?
  • 原文地址:https://www.cnblogs.com/zhaotianff/p/10797057.html
Copyright © 2020-2023  润新知