关于我想要编写dll文件这件事

Ustinain
• 阅读 2289

0x1前言

首先我们要用C、C++编写dll,肯定是需要一个合适的编写软件,什么!?你不知道什么是dll,那你这有必要去看看我得上一篇《初识Windows APi》了虽然篇幅不长,但是可以让你对dll有个大致得印象,由于本人用的CLion 2019的版本的,至于为什么不用VS,因为里面配置过于繁琐,很不友好,CLion安装包以及破解 群文件都有,可以去下载直接使用。话不多说,进入今天的正题:


利用C、C++简单的编写一个DLL文件

::: tip 开发环境:CLion 2019.3.3 编译器:WinGW64 ::: 打开CLion 新建一个 C Library项目DLL 关于我想要编写dll文件这件事 library.c默认代码 关于我想要编写dll文件这件事 按下Ctrl+F9编译,右侧生成libDLL.dll文件 关于我想要编写dll文件这件事

调用dll

新建一个项目 untitled1 ,在untitled1下创建一个lib目录,存放刚刚生成的dll文件, 关于我想要编写dll文件这件事 配置CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
#项目名
project(untitled1 )

set(CMAKE_C_STANDARD 99)

#新增:指项目根目录下的lib目录
link_directories(lib)

add_executable(untitled1 main.c )

#新增:目标链接的dll文件
target_link_libraries(untitled1 libDLL.dll)

配置main.c:

#include <stdio.h>
void hello();
int main() {
    printf("下面是一个dll的调用");
    hello();
    getchar();
    return 0;
}

配置Configurations: 将lib目录的绝对路径填入(如用群里的中文插件可能导致这里显示异常) 关于我想要编写dll文件这件事 然后编译运行结果如下: 关于我想要编写dll文件这件事 到这里只是用实操演示一下dll的由来,只能对编写dll有一个认识,当然无法准确的理解,那么请继续往下看


详解

这里介绍一下dll动态链接库的核心入口函数 DLLMain() 跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain。 以"DllMain"为关键字,来看看MSDN帮助文档怎么介绍这个函数的。

The DllMain function is an optional method of entry into a dynamic-link library (DLL) 。 (简要翻译:对于一个Dll模块,DllMain函数是可选的。)这句话很重要,很多初学者可能都认为一个动态链接库肯定要有DllMain函数。其实不然,像很多仅仅包含资源信息的DLL是没有DllMain函数的。

#include <windows.h>
_Bool WINAPI DllMain(HINSTANCE hinstDLL,  // handle to DLL module       
                    DWORD fdwReason,     // reason for calling function 
                    LPVOID lpReserved )  // reserved                    
{                                                                       
    // Perform actions based on the reason for calling.                 
    switch( fdwReason)                                                  
    {                                                                   
    case DLL_PROCESS_ATTACH:                                            
    // Initialize once for each new process.                            
    // Return FALSE to fail DLL load.                                   
        break;                                                          

    case DLL_THREAD_ATTACH:                                             
    // Do thread-specific initialization.                               
        break;                                                          

    case DLL_THREAD_DETACH:                                             
    // Do thread-specific cleanup.                                      
        break;                                                          

    case DLL_PROCESS_DETACH:                                            
    // Perform any necessary cleanup.                                   
        break;                                                          
}                                                                       
    return TRUE;  // Successful DLL_PROCESS_ATTACH.                     
}                                                                       

因为返回类型是布尔类型,所以最后要return true hinstDLL参数:DLL模块的句柄。该值是DLL的基地址;

fdwReason [in]参数:指明了DLL被调用的原因,可以有以下4个取值: ::: tip

1. DLL_PROCESS_ATTACH: 当DLL被进程 <第一次>调用时,导致DllMain函数被调用, 同时ul_reason_for_call的值为DLL_PROCESS_ATTACH, 如果同一个进程后来再次调用此DLL时,操作系统只会增加DLL的使用次数, 不会再用DLL_PROCESS_ATTACH调用DLL的DllMain函数。

2.DLL_PROCESS_DETACH: 当DLL被从进程的地址空间解除映射时,系统调用了它的DllMain,传递的ul_reason_for_call值是DLL_PROCESS_DETACH。 ★如果进程的终结是因为调用了TerminateProcess,系统就不会用DLL_PROCESS_DETACH来调用DLL的DllMain函数。这就意味着DLL在进程结束前没有机会执行任何清理工作。

3.DLL_THREAD_ATTACH: 当进程创建一线程时,系统查看当前映射到进程地址空间中的所有DLL文件映像,并用值DLL_THREAD_ATTACH调用DLL的DllMain函数。 新创建的线程负责执行这次的DLL的DllMain函数, 只有当所有的DLL都处理完这一通知后,系统才允许线程开始执行它的线程函数。

4.DLL_THREAD_DETACH: 如果线程调用了ExitThread来结束线程(线程函数返回时,系统也会自动调用ExitThread),系统查看当前映射到进程空间中的所有DLL文件映像,并用DLL_THREAD_DETACH来调用DllMain函数,通知所有的DLL去执行线程级的清理工作。 ::: ::: warning ★如果线程的结束是因为系统中的一个线程调用了TerminateThread,系统就不会用值DLL_THREAD_DETACH来调用所有DLL的DllMain函数。 ::: lpReserved参数:系统保留,不让我们利用,目前没什么意义。 不过关于lPReserved参数,看到一位网友是这样说的:

“lpvReserved:为零表示隐式载入,不为零表示显示载入 不是没有什么意义”,我还没有深究,暂做参考

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Nginx反向代理upstream模块介绍
!(https://oscimg.oschina.net/oscnet/1e67c46e359a4d6c8f36b590a372961f.gif)!(https://oscimg.oschina.net/oscnet/819eda5e7de54c23b54b04cfc00d3206.jpg)1.Nginx反
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这