近来又有人在群里问如何用c语言编制dll文件(动态链接库)。
原来没有对这个问题太在意过,也没有尝试过任何解决方案,毕竟原来我是用vb的(现在用.net),做个dll只不过是点选一下建立activeX dll工程的图标而已。今天在网上与朋友聊天,看了他指给我的几个几个文件,用MingW将C程序编译成dll文件的例子,我恍然大悟,原来讲C程序编译成dll文件只不过是在要公开的接口函数声明前面加上几个特定的修饰符而已。于是用dev-cpp建了个dll的默认文档,一切都很明了。(我把源代码贴在下面)
/*dll.h文件*/
#ifndef _DLL_H_ #define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport) #else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport) #endif /* Not BUILDING_DLL */
DLLIMPORT void HelloWorld (void);
#endif /* _DLL_H_ */
/*dllmain.c文件*/
/* Replace \#include \
#include
DLLIMPORT void HelloWorld () {
MessageBox (0, \}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ , DWORD reason /* Reason this function is being called. */ , LPVOID reserved /* Not used. */ ) {
switch (reason)
{
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH: break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break; }
/* Returns TRUE on success, FALSE on failure */ return TRUE; }
关于以上代码的几点解释: 一、__declspec (dllexport):这是关键,它标志着这个这个函数将成为对外的接口。(以下是我在网上下载的dllexport、dllimport、_declspec的一些说明):
使用包含在DLL的函数,必须将其导入。导入操作时通过dllimport来完成的,dllexport和dllimport都是vc(visual C++)和bc(Borland C++)所支持的扩展的关键字。但是dllexport和dllimport关键字不能被自身所使用,因此它的前面必须有另一个扩展关键字__declspec。通用格式如下:__declspec(specifier)其中specifier是存储类标示符。对于DLL,specifier将是dllexport和dllimport。而且为了简化说明导入和导出函数的语句,用一个宏名来代替__declspec.在此程序中,使用的是DllExport。如果用户的DLL被编译成一个C++程序,而且希望C程序也能使用它,就需要增加“C”的连接说明。#define DllExport extern \,这样就避免了标准C++命名损坏。(当然,如果读者正在编译的是C程序,就不要加入extern “C”,因为不需要它,而且编译器也不接受它)。
二、BOOL APIENTRY DllMain ()说明:(以下是我在网上收集的资料)
1、每一个DLL必须有一个入口点,DllMain是一个缺省的入口函数。DllMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DllMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DllMain。 DllMain的函数原型:
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVO
ID lpReserved) {
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH: .......
case DLL_THREAD_ATTACH: .......
case DLL_THREAD_DETACH: .......
case DLL_PROCESS_DETACH: .......
return TRUE; } }
参数:
hMoudle:是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);
ul_reason_for_call:是一个说明动态库被调原因的标志。当进程或线程装入或卸载动态连接库的时候,操作系统调用入口函数,并说明动态连接库被调用的原因。它所有的可能值为:
DLL_PROCESS_ATTACH: 进程被调用; DLL_THREAD_ATTACH: 线程被调用; DLL_PROCESS_DETACH: 进程被停止; DLL_THREAD_DETACH: 线程被停止; lpReserved:是一个被系统所保留的参数。
看到这里,我想大家应该会对将c程序编译成dll文件有了个大体的概念。
关于对于dll文件的使用,我在vb.net里做了以下测试: 首先用vs.net 2003新建一个vb.net应用程序。
然后在工程属性中引用System.Runtime.InteropServices命名空间。 然后在默认的窗体文件中添加如下代码: Public Class Form1
Inherits System.Windows.Forms.Form
#Region \窗体设计器生成的代码 \
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub