在MinGW下创建DLL(DLL Creation in MingW)

本文指导新手程序员如何在免费开发环境MinGW下创建动态链接库(DLL),包括DLL的基本概念、创建过程及实现一个简单的HelloWorld示例。

I've always considered DLLs to be esoterically cool stuff - somehow the idea of one program running another makes my imagination run wild. I've now discovered that in many cases DLLs are a bad idea(TM), but for a fledgling programmer, learning how to create a DLL, especially in a free development environment such as MingW would mean an instant familiarity with a lot of development tools, and a lot of the seemingly hidden options of the incredible gcc compiler.

As usual, we're diving in. You should have a copy of mingw handy. Get the MingW installer from the Current branch in the Mingw download page , that sets you off easy. You should also be familiar with IDE-less coding, or should know enough to set up an IDE to work with Mingw, I'm not going to cover that here.

What are DLLs?

First off, what are DLLs? DLLs are dynamically linked libraries. How are they different from static libraries? In static libraries, the linking is done at compile time: all the library functions are combined with the main fragment of program code to create the executable. When the linking is done at runtime, it is called dynamic linking. Since the linking is done at runtime, it is obvious that the operating system will have something to do with it. That is why most DLL implementations are non-portable.

When a compiled executable that references a DLL is loaded, the OS looks into the file and sees that the executable references a set of "imports" from a DLL file. This is simply a situation equivalent to finding that "This program uses the following functions which are contained in this dll". The OS then looks into the particular DLL. The DLL has a corresponding and matching set of export functions that the OS then maps from the functions referenced in the main executable to the functions in the DLL. Thus, when the executable calls a referenced function, the code in the DLL is executed. Viola! Dynamic linking!

Hello DLL!

I'm now going to describe a standard "Hello world" implementation. The code is in three files: hello.c, dll.h and dll.c. The code is listed and explained below:

hello.c

#include <stdio.h>	
#include "dll.h"

int main () {
hello();
return 0;
}

Hello.c is a standard hello world C program except that the hello() function is going to be dynamically linked. The only special thing here is the inclusion of dll.h.

dll.h

#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif

EXPORT void hello(void);

DLL.h is where most of the magic happens. It begins with checking the BUILD_DLL macro. We manually set this macro when building so that the macro EXPORT is set to __declspec(dllexport) , so that gcc can build the dll. When the OS calls up the dll from the executable, BUILD_DLL is not set and therefore EXPORT is set to __declspec(dllimport) which is a nice set of macro routines to expose our function to the calling scope.

Note that __declspec(dllexport) and __declspec(dllimport) are mingw macros to faciliate DLL creation. They are mapped to their equivalent WinAPI headers.

dll.c

#include 
#include "dll.h"

EXPORT void hello(void) {
printf ("Hello/n");
}

This is the actual code of the hello world routine. There should be nothing special here.

Compiling and Linking the files

DLL creation used to be a tiresome process. Recent advances in gcc and mingw engines have meant that it takes only four steps now to create a dll. They are:

  1. Creating the object code for hello.c
  2. gcc -c hello.c
  3. Creating the object code for the dll
  4. gcc -c -DBUILD_DLL dll.c

    Notice the use of the -D param by which we set the macro BUILD_DLL. It is used for setting export to __declspec(dllexport) so that compilation can take place.

  5. Creating the dll
  6. gcc -shared -o message.dll dll.o -Wl,--out-implib,libmessage.a

    The third step requires more explanation.
    The -shared parameter is used for creating a shared libaray; in Win platform it is a dll.
    -Wl means wait for next message to the linker.
    --out-implib is a param to the linker ld which tells it to create an import library which is used by programs which want to link to your dll.
    We are ignoring the definitions file which every well-behaved dll should export. If you follow the step above, GCC will automatically create the definition. For most cases, it will work, but if you want to optimize stuff this is the place to look.

  7. Creating the executable
  8. gcc -o hello.exe hello.o message.dll

    The fourth step is actually a bit of gcc magick. The actual step is something like this:

    gcc -o hello.exe hello.o -L./ -lmessage

    The -L param means that the linker checks the ./ path for imports
    -lmessage (or -l message) means to search for the message linker name. It extracts this from message.dll

Once you've finished these steps, run the program!

C:/>hello
Hello!

Wait, that's not dynamic!

You're right, that's not *really* dynamic. Of course, you're loading the function at run-time, but what is the purpose of that if you need to reference the dll at compile-time? One of the reasons why a dll is used is to enable a plugin architecture for your program. Other people can write code that your program can use, and you can't really anticipate other people's dlls, and if you are going to recompile your program every time a new dll comes along, then why use dynamic linking at all?

Solve this by using two functions from the Windows API: LoadLibrary() and GetProcAddress(). We modify the codes for the main module like this:

hello.c

#include <windows.h>
#include <stdio.h>

int main () {

/*Typedef the hello function*/
typedef void (*pfunc)();

/*Windows handle*/
HANDLE hdll;

/*A pointer to a function*/
pfunc hello;

/*LoadLibrary*/
hdll = LoadLibrary("message.dll");

/*GetProcAddress*/
hello = (pfunc)GetProcAddress(hdll, "hello");

/*Call the function*/
hello();
return 0;
}

The code should be self explanatory, there are just some things that you should remember:

  1. Don't forget to include windows.h
  2. The syntax for LoadLibrary is:
  3. handle = LoadLibrary("path to dll file");

    handle is <= HINSTANCE_ERROR if there is an error loading the dll.

  4. The syntax for GetProcAddress is:
  5. pointer_to_function = (pointer_to_function_type)GetProcAddress(dll_handle, "resource_name");

    We can also use global variables inside the dll that are prefixed with export as a valid resource name, it needn't be a function. That is,

    variable = (type)GetProcAddress(dll_handle, "global_variable_name_inside_dll");

    is also valid.

  6. For further error info at any step in the process, call GetLastError()

To compile it, don't change a thing for the dlls. For compiling hello.c, a simple...

gcc -o hello.exe hello.c
...would do.

在许多情况下使用DLL是一个糟糕的主意,但对于新手来说学会如何创建DLL,尤其是一个免费的开发环境例如MinGW将意味着对开发工具的快速熟悉并能了解那些看起来隐含的选项。
  
  在继续下面的内容之前,你应该已经安装并且配置好了MinGW。同样你应该对缺少IDE环境的编程比较熟悉,或者知道如何在IDE环境下使用MinGW。这里就不再对此进行详细说明了。
  
  什么是DLL
   什么是DLL呢?DLL全称dynamically linked libraries (动态连接库)。它和静态连接库有什么区别呢?在静态连接库中,连接是在编译时完成的,库函数代码被添加到了主程序中。而在运行时完成连接的就叫动态连 接。因为连接是在运行时完成的,显然操作系统将为此做一些幕后工作。这也是为什么大多数DLL不可移植的原因。
  
  当一个引用了 DLL的可执行文件被加载,操作系统查找所有包含”imports”的连接,也就是查找使用了DLL功能的地方。然后操作系统去查找具体的DLL,如果在 DLL中找到和这个”imports”匹配的”exports”,操作系统会对此做一个映射。这样可执行文件调用一个”imports”函数,DLL中的 代码将会执行。哇,这就是动态连接。
  
  Hello DLL
  下面我将描述一个”hello world”的实现。代码由三个文件组成:hello.c、dll.h和dll.c。
  代码如下:
  hello.c
  #include <stdio.h>
  #include <dll.h>
  int main()
  {
   hello();
   return 0;
  }
  除了hello()函数使用动态连接外,hello.c是一个标准的hello world C程序。唯一特别的地方就是它包含了一个dll.h文件。
  
  dll.h
  #ifdef BUILD_DLL
  /* DLL export */
  #define EXPORT __declspec(dllexport)
  #else
  /* EXE import */
  #define EXPORT __declspec(dllimport)
  #endif
  
  EXPORT void hello(void);
   Dll.h有一些技巧性的东西在里面。它检查这个BUILD_DLL宏。当我们编译时将手动设置BUILD_DLL宏,这时候宏EXPORT被设置成 __declspec(dllexport)。这样GCC就能编译这个DLL。当从可执行文件中调用DLL时,BUILD_DLL宏没有被设 置,EXPORT宏被设置成__declspec(dllimport), 它将使函数在调用范围内可见。
  
  __declspec(dllexport)和__declspec(dllimport)是用来创建DLL的宏。
  
  dll.c
  #include "dll.h"
  EXPORT void hello(void)
  {
  printf ("Hello/n");
  }
  这是hello world 实际实现代码,这里没有什么特别的。
  
  编译连接程序
  1、 编译hello.c
   gcc -c hello.c
  2、 编译dll.c
   gcc -c -DBUILD_DLL dll.c
   注意要使用要使用-DBUILD_DLL来设置宏BUILD_DLL
  3、 创建dll
  gcc -shared -o message.dll dll.o -Wl,--out-implib,libmessage.a
  这一步要详细说明一下
  -shared参数用来创建共享库,在windows中为dll
  -Wl 等待下一条信息进行连接
  --out-implib是给连接程序ld使用的,用于创建要连接dll需要的import library
  4、 创建可执行文件
  gcc -o hello.exe hello.o -L./ -lmessage
  -L 指定连接库路径
  -lmessage (or -l message) 指定dll的import library
  
  好了,编译连接完成,运行程序
  C:/>hello
  Hello!(王朝网络 wangchao.net.cn)
内容概要:本文设计了一种基于PLC的全自动洗衣机控制系统内容概要:本文设计了一种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔和过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及和柔和、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能和、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识和梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制类项目开发参考一定PLC基础知识。; 阅读和梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中类似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件和MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值