磁盘

磁盘相关的 API 函数:

GetLogicalDriveStrings:获取所有的逻辑盘符

GetDriveType:获取类型

GetDiskFreeSpace:获取磁盘空间的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "pch.h"
#include<windows.h>
#include<stdio.h>
#include<tchar.h>
#include <locale.h>
int main()
{
int nLen = 1;
int uDriveType = 0;
//1 获取所有的逻辑驱动器的盘符
TCHAR buf[200] = {};
TCHAR *pStr = NULL;
GetLogicalDriveStrings(200, buf);
pStr = buf;
//注意:有一个设置语言的函数
_tsetlocale(LC_ALL, _T("chs"));
while (nLen!=0)
{
_tprintf(_T("%s "), pStr);
//2 获取逻辑驱动器的类型
uDriveType = GetDriveType(pStr);
switch (uDriveType)
{
case DRIVE_FIXED:
_tprintf(_T("硬盘"));
break;
case DRIVE_CDROM:
_tprintf(_T("光驱"));
break;
case DRIVE_REMOTE://远程的
_tprintf(_T("远程的"));
break;
case DRIVE_REMOVABLE://可移动的
_tprintf(_T("可移动的"));
break;
case DRIVE_UNKNOWN://未知的
_tprintf(_T("未知的"));
break;
break;
default:
break;
}
//3 获取磁盘的空间信息
DWORD 每簇扇区数量 = 0;
DWORD 扇区容量 = 0;
DWORD 空闲簇总量 = 0;
DWORD 全部簇总量 = 0;
GetDiskFreeSpace(
pStr,
&每簇扇区数量, &扇区容量,
&空闲簇总量, &全部簇总量
);
_tprintf(_T("总容量:%lfGB "), (全部簇总量/1024.0)*每簇扇区数量*扇区容量/1024/1024);
_tprintf(_T("空闲容量:%lfGB"), (空闲簇总量/1024.0)*每簇扇区数量*扇区容量/1024/1024);

nLen = _tcslen(pStr);
pStr += nLen + 1;
_tprintf(_T("\n"));
}
}

动态链接库

创建一个动态链接库文件:

1571723909815

创建完 DLL 工程后会出现一个 DllMain 函数,它与传统的 mainWinMain 函数不同,因为 dll 文件不像 exe 文件一样直接运行,它是提供函数给其他程序使用的,不需要入口这样的概念,所以 dll 文件被执行的第一行代码并非是 DllMain

当程序被创建、程序中有线程被创建、程序即将退出、程序中有线程将要退出时会调用 DllMain 函数

导出 dll 的方式:

  1. 声明导出:

    .h 文件中进行声明

    1
    2
    #pragma once
    extern "C" _declspec(dllexport) int Add(int a, int b);

    .cpp 中实现

    1
    2
    3
    4
    5
    6
    7
    #include "Dll1.h"
    extern "C" int Add(int a, int b) {
    return a + b;
    }
    int Sub(int a, int b) {
    return a - b;
    }

    编译成功后,就可看到 dll 文件

    1571728802574

    使用 PEiD v0.95 查看 dll 文件的导出表,其中存储了 dll 文件的导出函数 Add,只有函数导出了才能给其他模块使用

    1571729152073

  1. def 文件导出:

    .cpp 中实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include "stdafx.h"
    #include <stdio.h>
    int Fun(){
    printf("Hello world");
    return 0;
    }
    int Fun2(){
    printf("Hello 15pb");
    return 0;
    }
    int Fun1(){
    printf("你好 十五派");
    return 0;
    }

    先制作一个 def 脚本文件

    1571730426047

    然后设置工程属性:

    1571730475065

    最后编译,使用 PEiD v0.95 查看,导出成功

1571730360652

使用 dll 文件的方式:

  1. 隐式链接

    添加一个空项目,包含头文件,载入 lib 文件,调用函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //1 包含头文件
    //#include "C:\\Users\\SouLinker\\source\\repos\\TestDll_36\\Dll1\\Dll1.h"
    #include "..\\Dll1\\Dll1.h"
    //2 载入lib文件
    #pragma comment(lib, "..\\Debug\\Dll1.lib")
    int main()
    {
    int nNum1 = 10;
    int nNum2 = 5;
    int nSum = Add(nNum1, nNum2);//只能使用导出了的函数
    //int nSub = Sub(nNum1, nNum2);
    return 0;
    }
  1. 显示链接:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include<iostream>
    #include<windows.h>
    #include<tchar.h>
    typedef int(*ADD)(int a, int b);
    ADD g_pFunAdd = NULL;
    int main()
    {
    int nNum1 = 10;
    int nNum2 = 5;
    //1载入dll
    HMODULE hModule = LoadLibrary(_T("Dll1.dll"));
    //2根据函数名得到函数地址
    g_pFunAdd = (ADD)GetProcAddress(hModule, "Add");
    //3调用函数
    int nRe = g_pFunAdd(nNum1, nNum2);
    //4释放
    FreeLibrary(hModule);
    return 0;
    }

隐式链接会暴露 dll 的调用信息:

1571733492196

显示链接不会暴露此信息:

1571733558002

探讨动态链接库和静态链接库

dll 是动态链接库:代码和数据都不会放在 exe 中,而是在程序运行时加载,缺点就是发布程序必须一起发布,否则无 dll 程序就无法运行

动态链接库增强了模块性,使用 dll 不需要关注功能怎么实现,只需包含头文件,将 dll 放到 exe 所在目录下,就可使用其中的函数;使用动态链接库更新软件更加方便,将程序分为多个部分,更新时也许只需更新其中几个 dll 即可,或更新 exe 也行,只要接口不变;windows 通过这种机制取节约内存

动态链接库的缺点:若某一个 dll 丢失或损坏,程序就运行不起来

若希望只发布 exe 程序就能使用,可以使用静态链接库

1571734029773

其他的声明导出,隐式链接和动态链接库的使用是一样的

编译动态链接库时,生成一个 dll 文件和一个 lib 文件,其中 lib 文件称为导入库,不包含代码和数据,只包含一些链接信息,链接器用它来解析代码中的函数调用

编译静态链接库时,会生成一个 lib 文件,称为对象库,包含代码和数据,在运行链接器时被添加到程序的 .exe 文件中