荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Dreamer (梦想的彼岸), 信区: Program
标  题: Re: 请教怎么编DLL和怎么使用,用C语言的????? ┅
发信站: 荔园晨风BBS站 (Thu Mar 25 21:55:51 2004), 站内信件

CSDN的文章,慢慢看:)


主  题:  大家来总结"VC环境下DLL编写的相关知识", 200分哦~
作  者:  fengzi_zhu (才知道自己还是初学者)
等  级:
信 誉 值:  100
所属论坛:  VC/MFC 进程/线程/DLL
问题点数:  200
回复次数:  94
发表时间:  2003-3-25 12:15:55




鉴于最近重复问DLL制作的问题,本人做了小小的总结
     欢迎大家提出意见,予以修改补充.最好要能把本篇列入FAQ中.

                VC环境下DLL编写的相关知识

   使用VC模板可以生成以下三种不同类型的DLL:
   1.Win32DLL
      只能导出C函数和变量,但可以使用除CObject派生的类.不能在
   导出函数中建立对话框,因为不能进行模块环境转换.

   2.MFC常规DLL
      只能导出C函数和变量,但可以使用MFC中所有的类,在使用DLL中的资源
   时要进行模块环境转换,在每个要导出的函数最前面加上:
   AFX_MANAGE_STATE(AfxGetStaticModuleState())
   也可以使用以下人工转换:
   HINSTANCE hCurContext = AfxGetResourceHandle();
AfxSetResourceHandle(::GetModuleHandle("temp.dll"));
   //可以使用DLL中的资源了.
   HRSRC hRes = FindResource(hCurContext,MAKEINTRESOURCE(129),
                        RT_DIALOG);
   .....//可以创建窗口了

   AfxSetResourceHandle(hCurContext);
   另外标准C语言中不支持重载,因为C语言的调用协定(__cdecl)生成的代码中函
  数名只有一个_(下划线)做前缀,所有该类型的DLL不能导出重载函数.

   3.MFC扩展DLL
      支持C++接口,可以导出C++类,成员函数及重载函数,只支持动态MFC库.
   其实我们使用的MFC42.dll就属于该类.
      在该类AFX DLL中导出的C++类成员函数不使用extern "C",因为C++类使用
  的是this调用协定, 该协定没有C的换名规则.
      VC模板使用new CDynLinkLibrary(CqDLL);将该DLL加入资源链表中.
   所以对资源的搜索顺序如下:
      1.当EXE文件需要资源时,先从EXE模块中查找,然后搜索DLL模块,最后
        查找MFC Ext DLL模块(mfc42.dll).
      2.当DLL使用资源时,其搜索顺序如下:
        DLL ---> MFC Ext DLL ---> EXE(调用该DLL的进程模块)







 回复人: maoxianwang(大大㊣BETAⅡ //楼主,请把分给猪) ( ) 信誉:97
2003-3-25 12:18:00  得分:0



还有啥说的呢?

想不起来呀



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-25 12:
28:12  得分:0



要不要敲一敲啊~



Top

 回复人: smartpiglet(小猪) ( ) 信誉:100  2003-3-25 13:28:08  得分:0



这些算不算??
typedef HRESULT (__stdcall * _fn)(IKTestCase**);

HINSTANCE hDll = ::LoadLibrary("ettest.dll");
        if (hDll)
        {
                _fn pfn = (_fn)::GetProcAddress(hDll, "ETTestCase");
                r = pfn(&TCase);
        }

------------------------------------------------------------------------

#include "stdafx.h"
#include "KTestCase.h"

HRESULT __stdcall ETTestCase(IKTestCase** itc)
{
        IKTestCase* _itc = NULL;
        _itc = new KTestCase;
        *itc = _itc;
        return S_OK;
}



另外的方法:

如何快速使用DLL
加载dll,使用DLL的Function,

 void __fastcall TForm1::Button1Click(TObject *Sender)
{
  HINSTANCE hinstDlltest =LoadLibrary("capi.dll");
  if (hinstDlltest)!= NULL
{
    /*
    Do something here....
    */
}
else
{
    ....
}

*DLL 应在 Window/system (for 95 98) 下, nt 在 Winnt/system 下,不然DLL 就
一定要和执行程序在同一个目录,或者 LoadDLL 可以指定 Path。
LoadLibrary("c:\\temp\\capi.dll");


//
首先要知道 dll 文件中的函数 例:InitializeWinIo();
在头文件中写成:
WINIO_API bool _stdcall InitializeWinIo();

在主文件中使用::

//
HINSTANCE ghDLL=NULL;
ghDLL = LoadLibrary("*.dll")

GetProcAddress(ghDLL, "dll 中的函数名")

FreeLibrary(ghDLL)





Top

 回复人: hanwg() ( ) 信誉:100  2003-3-25 14:31:26  得分:0



up



Top

 回复人: RomanticProgrammer() 兰企鹅||南极俺最帅 () ( ) 信誉:105
2003-3-25 14:36:44  得分:0



学习+收藏。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-25 15:
12:42  得分:0



smartpiglet(小猪)
  你说的是在明式调用DLL时,对DLL的搜索次序问题.



Top

 回复人: icansaymyabc(学习与进步) ( ) 信誉:100  2003-3-25 15:46:41  得
分:0



1.Win32DLL
      只能导出C函数和变量,但可以使用除CObject派生的类.
  不能在导出函数中建立对话框,因为不能进行模块环境转换.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
错:
   我就写了一个DLL中的对话框,不信我发给你看,留下E-Mail。



Top

 回复人: CQP(悄悄的我走了,正如我悄悄的来) ( ) 信誉:100  2003-3-26 9:
56:47  得分:0



thanks for your hard work,i think everybody will like it.
mark first



Top

 回复人: netxy(netxy) ( ) 信誉:100  2003-3-26 10:03:11  得分:0



Onething bears noting: you can use extern "C" to extinguish the name
mangle of C++ functions. or you can use a .def file to export designated
 function name; another alternative is a #pragma comment(linker,
"/export:func=_func@4"), which is used for _stdcall functions.
And also, the member functions of a C++ class can never be exported, nor
 do the overloaded functions(only one version of them can be exported.
)



Top

 回复人: abc_rain() ( ) 信誉:110  2003-3-26 10:14:00  得分:0



一、 什么是动态链接库?
动态链接库其实就是为应用程序提供服务并具有某一特定功能的函数和类的集合。
与它相对的是静态链接库。

二、 动态链接库与静态链接库有什么区别呢?
1、 如果程序调用静态链接库中的函数,静态链接库在链接阶段将库中该函数所
包含的代码拷贝至运行文件中,而动态链接库则是在运行时动态的把静态链接库中
要用到的函数装入内存,并在内存中形成一份拷贝以供应用程序调用,这就是为什
么如何你在编绎前如果选功能project->Settings->Gennerl->Microsoft
Foundation Classes:->Use MFC in a Static DLL 那么要比选Use MFC in a
Shared DLL 编绎出来的程序大很多的原因。
2、 动态链接库可以实现串行口、并行口等外设的资源共享,静态链接库就不行

3、 静态链接库目标代码为Lib文件,动态链接库目标代码为Dll和Lib文件。

三、 动态链接库的应用范围?
1、 多个应用程序共享代码和数据:比如:Office软件的各个组成部份都有相似的
外观和功能,这就是通过共享动态链接库实现的。
2、 在钩子程序(HOOK)过滤系统消息时必须使用动态链接库
3、 设备驱动程序必须是动态链接库。
4、 如果要在对话框编辑器中使用自定义的控件,也必须使用动态链接库
5、 要实现多语言版本,使用动态链接库是一个很好的选择。

四、 动态链接库的创建方式与创建方式的不同
MFC支持两类动态链接库的创建方式:
1、 MFC常规动态链接库特点:
不能导出C++类、成员函数、重载函数,允许静态或动态链接MFC类库。
静态链接MFC常量设置:_USERDLL
动态链接MFC常量设置:_USERDLL、_AFXDLL
2、 MFC扩展动态链接库特点:
能导出C++类、成员函数、重载函数等等,只允许动态链接MFC类库。
动态链接MFC常量设置:_AFXEXT、_AFXDLL
五、 应用范围:
1、 当导出的函数既能够用于VC,还能用于VB、PB等Win32环境时,要使用MFC常
规DLL。
2、 如果需要充分利用MFC类库的资源时,要使用MFC扩展DLL。
3、 当需要导出C++类、成员函数、重载函数、资源时,要使用MFC扩展DLL。





Top

 回复人: diabloqin(fuckmachine) ( ) 信誉:100  2003-3-26 10:30:34  得分
:0



感谢楼主,收藏



Top

 回复人: flyycyu(fly) ( ) 信誉:100  2003-3-26 10:34:37  得分:0



up



Top

 回复人: Gladstone(大士) ( ) 信誉:111  2003-3-26 10:55:48  得分:0



gz



Top

 回复人: dawn33(孤独的海) ( ) 信誉:100  2003-3-26 10:58:40  得分:0



一、关于调用方式:

1、静态调用方式:由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码
(如还有其它程序使用该DLL,则Windows对DLL的应用记录减1,直到所有相关程序
都结束对该DLL的使用时才释放它),简单实用,但不够灵活,只能满足一般要求
。 隐式的调用:需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程
中,想使用DLL中的函数时,只须说明一下。隐式调用不需要调用LoadLibrary()和
FreeLibrary()。程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应
的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是
并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。当程
序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中
导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB文件中也包含了
对应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。当
应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,
然后通过符号名或标识号实现对DLL函数的动态链接。所有被应用程序调用的DLL文
件都会在应用程序EXE文件加载时被加载在到内存中。可执行程序链接到一个包含
DLL输出函数信息的输入库文件(.LIB文件)。操作系统在加载使用可执行程序时加
载DLL。可执行程序直接通过函数名调用DLL的输出函数,调用方法和程序内部其他
的函数是一样的。






Top

 回复人: dawn33(孤独的海) ( ) 信誉:100  2003-3-26 10:59:14  得分:0



2、动态调用方式:是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,使
用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。

显式的调用:是指在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的
将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,
再用GetProcAddress()获取想要引入的函数。自此,你就可以象使用如同本应用程
序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用
FreeLibrary或MFC提供的AfxFreeLibrary释放动态连接库。直接调用Win32 的
LoadLibary函数,并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数,应
用程序在调用GetProcAddress函数时使用这一参数。GetProcAddress函数将符号名
或标识号转换为DLL内部的地址。程序员可以决定DLL文件何时加载或不加载,显式
链接在运行时决定加载哪个DLL文件。使用DLL的程序在使用之前必须加载(
LoadLibrary)加载DLL从而得到一个DLL模块的句柄,然后调用GetProcAddress函
数得到输出函数的指针,在退出之前必须卸载DLL(FreeLibrary)。

Windows将遵循下面的搜索顺序来定位DLL:
1.包含EXE文件的目录,
2.进程的当前工作目录,
3.Windows系统目录,
4.Windows目录,
5.列在Path环境变量中的一系列目录。 二、MFC中的dll:

a、Non-MFC DLL:指的是不用MFC的类库结构,直接用C语言写的DLL,其输出的函数
一般用的是标准C接口,并能被非MFC或MFC编写的应用程序所调用。

b、Regular DLL:和下述的Extension Dlls一样,是用MFC类库编写的。明显的特点
是在源文件里有一个继承CWinApp的类。其又可细分成静态连接到MFC和动态连接到
MFC上的。

静态连接到MFC的动态连接库只被VC的专业般和企业版所支持。该类DLL应用程序里
头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。输入函数有如
下形式:
extern "C" EXPORT YourExportedFunction( );
如果没有extern “C”修饰,输出函数仅仅能从C++代码中调用。
DLL应用程序从CWinApp派生,但没有消息循环。

动态链接到MFC的规则DLL应用程序里头的输出函数可以被任意Win32程序使用,包
括使用MFC的应用程序。但是,所有从DLL输出的函数应该以如下语句开始:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
此语句用来正确地切换MFC模块状态。

Regular DLL能够被所有支持DLL技术的语言所编写的应用程序所调用。在这种动态
连接库中,它必须有一个从CWinApp继承下来的类,DllMain函数被MFC所提供,不
用自己显式的写出来。

c、Extension DLL:用来实现从MFC所继承下来的类的重新利用,也就是说,用这种
类型的动态连接库,可以用来输出一个从MFC所继承下来的类。它输出的函数仅可
以被使用MFC且动态链接到MFC的应用程序使用。可以从MFC继承你所想要的、更适
于你自己用的类,并把它提供给你的应用程序。你也可随意的给你的应用程序提供
MFC或MFC继承类的对象指针。Extension DLL使用MFC的动态连接版本所创建的,并
且它只被用MFC类库所编写的应用程序所调用。Extension DLLs 和Regular DLLs不
一样,它没有一个从CWinApp继承而来的类的对象,所以,你必须为自己DllMain函
数添加初始化代码和结束代码。 和规则DLL相比,有以下不同:

1、它没有一个从CWinApp派生的对象;
2、它必须有一个DllMain函数;
3、DllMain调用AfxInitExtensionModule函数,必须检查该函数的返回值,如果返
回0,DllMmain也返回0;
4、如果它希望输出CRuntimeClass类型的对象或者资源(Resources),则需要提供
一个初始化函数来创建一个CDynLinkLibrary对象。并且,有必要把初始化函数输
出;
5、使用扩展DLL的MFC应用程序必须有一个从CWinApp派生的类,而且,一般在
InitInstance里调用扩展DLL的初始化函数。





Top

 回复人: dawn33(孤独的海) ( ) 信誉:100  2003-3-26 10:59:25  得分:0



三、dll入口函数:

1、每一个DLL必须有一个入口点,DllMain是一个缺省的入口函数。DllMain负责初
始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程
的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束
时,都会调用DllMain。但是,使用TerminateProcess或TerminateThread结束进程
或者线程,不会调用DllMain。

DllMain的函数原型:
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID
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:是一个被系统所保留的参数。 2、_DllMainCRTStartup

为了使用“C”运行库(CRT,C Run time Library)的DLL版本(多线程),一个
DLL应用程序必须指定_DllMainCRTStartup为入口函数,DLL的初始化函数必须是
DllMain。

_DllMainCRTStartup完成以下任务:当进程或线程捆绑(Attach)到DLL时为“C”运
行时的数据(C Runtime Data)分配空间和初始化并且构造全局“C++”对象,当进
程或者线程终止使用DLL(Detach)时,清理C Runtime Data并且销毁全局“C++”对
象。它还调用DllMain和RawDllMain函数。

RawDllMain在DLL应用程序动态链接到MFC DLL时被需要,但它是静态的链接到DLL
应用程序的。在讲述状态管理时解释其原因。

四、关于约定:

动态库输出函数的约定有两种:调用约定和名字修饰约定。

1)调用约定(Calling convention):决定函数参数传送时入栈和出栈的顺序,由调
用者还是被调用者把参数弹出栈,以及编译器用来识别函数名字的修饰约定。

函数调用约定有多种,这里简单说一下:

1、__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的
VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了
__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用
约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在
返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰
部分在后面将详细说明)。

_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到
左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划
线前缀,在函数名后加上"@"和参数的字节数。

2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用
者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现
可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同
。 _cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈
的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到
左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用
约定。

3、__fastcall调用约定是“人”如其名,它的主要特点就是快,因为它是通过寄
存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参
数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内
存栈),在函数名修饰约定方面,它和前两者均不同。

_fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上
"@"前缀,在函数名后加上"@"和参数的字节数。

4、thiscall仅仅应用于“C++”成员函数。this指针存放于CX寄存器,参数从右到
左压。thiscall不是关键词,因此不能被程序员指定。

5、naked call采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代
码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内
容。naked call不产生这样的代码。naked call不是类型修饰符,故必须和
_declspec共同使用。

关键字 __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前,也可以
在编译环境的Setting...\C/C++ \Code Generation项选择。当加在输出函数前的
关键字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。它们对应
的命令行参数分别为/Gz、/Gd和/Gr。缺省状态为/Gd,即__cdecl。

要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定,至于函数名修饰约
定,可以通过其它方法模仿。还有一个值得一提的是WINAPI宏,Windows.h支持该
宏,它可以将出函数翻译成适当的调用约定,在WIN32中,它被定义为__stdcall。
使用WINAPI宏可以创建自己的APIs。

2)名字修饰约定

1、修饰名(Decoration name)

“C”或者“C++”函数在内部(编译和链接)通过修饰名识别。修饰名是编译器在
编译函数定义或者原型时生成的字符串。有些情况下使用函数的修饰名是必要的,
如在模块定义文件里头指定输出“C++”重载函数、构造函数、析构函数,又如在
汇编代码里调用“C””或“C++”函数等。

修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。

2、名字修饰约定随调用约定和编译种类(C或C++)的不同而变化。函数名修饰约定
随编译种类和调用约定的不同而不同,下面分别说明。 a、C编译时函数名修饰约
定规则:

__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号
和其参数的字节数,格式为_functionname@number。

__cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。


__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号
和其参数的字节数,格式为@functionname@number。

它们均不改变输出函数名中的字符大小写,这和PASCAL调用约定不同,PASCAL约定
输出的函数名无任何修饰且全部大写。 b、C++编译时函数名修饰约定规则:

__stdcall调用约定:
1、以“?”标识函数名的开始,后跟函数名;
2、函数名后面以“@@YG”标识参数表的开始,后跟参数表;
3、参数表以代号表示:
X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
....
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“0
”代替,一个“0”代表一次重复;
4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识
在其所指数据类型前;
5、参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结
束。

其格式为“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如
int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”
void Test2() -----“?Test2@@YGXXZ”

__cdecl调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“
@@YA”。

__fastcall调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“
@@YI”。

VC++对函数的省缺声明是"__cedcl",将只能被C/C++调用.

五、关于DLL的函数:

动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal
 function)。导出函数可以被其它模块调用,内部函数在定义它们的DLL程序内部
使用。

输出函数的方法有以下几种:

1、传统的方法

在模块定义文件的EXPORT部分指定要输入的函数或者变量。语法格式如下:
entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE]

其中:

entryname是输出的函数或者数据被引用的名称;

internalname同entryname;

@ordinal表示在输出表中的顺序号(index);

NONAME仅仅在按顺序号输出时被使用(不使用entryname);

DATA表示输出的是数据项,使用DLL输出数据的程序必须声明该数据项为
_declspec(dllimport)。

上述各项中,只有entryname项是必须的,其他可以省略。

对于“C”函数来说,entryname可以等同于函数名;但是对“C++”函数(成员函
数、非成员函数)来说,entryname是修饰名。可以从.map映像文件中得到要输出
函数的修饰名,或者使用DUMPBIN /SYMBOLS得到,然后把它们写在.def文件的输出
模块。DUMPBIN是VC提供的一个工具。

如果要输出一个“C++”类,则把要输出的数据和成员的修饰名都写入.def模块定
义文件。

2、在命令行输出

对链接程序LINK指定/EXPORT命令行参数,输出有关函数。

3、使用MFC提供的修饰符号_declspec(dllexport)

在要输出的函数、类、数据的声明前加上_declspec(dllexport)的修饰符,表示输
出。__declspec(dllexport)在C调用约定、C编译情况下可以去掉输出函数名的下
划线前缀。extern "C"使得在C++中使用C编译方式成为可能。在“C++”下定义“
C”函数,需要加extern “C”关键词。用extern "C"来指明该函数使用C编译方式
。输出的“C”函数可以从“C”代码里调用。

例如,在一个C++文件中,有如下函数:
extern "C" {void __declspec(dllexport) __cdecl Test(int var);}
其输出函数名为:Test

MFC提供了一些宏,就有这样的作用。

AFX_CLASS_IMPORT:__declspec(dllexport)

AFX_API_IMPORT:__declspec(dllexport)

AFX_DATA_IMPORT:__declspec(dllexport)

AFX_CLASS_EXPORT:__declspec(dllexport)

AFX_API_EXPORT:__declspec(dllexport



Top

 回复人: Cool_jxx() ( ) 信誉:100  2003-3-26 14:45:35  得分:0



导出C++类不一定非要MFC扩展DLL.这要看类是不是从MFC派生的.



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-26 14:
46:51  得分:0



最好不要简单的COPY书上的. 能用自己的语言总结一下...

都把自己遇到的问题总结出来.



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-26 14:
52:37  得分:0



TO Cool_jxx()
   可以吗? 你试过吗? 说说怎么导出的.



Top

 回复人: lins(*无间行者*) ( ) 信誉:95  2003-3-26 14:53:20  得分:0



mark



Top

 回复人: Cool_jxx() ( ) 信誉:100  2003-3-26 15:00:07  得分:0



可以导出.很简单
class _declspec(dllexport) CMyClass
{
public;
void test();
};

void CMyClass ::test()
{
    MessageBox(NULL,"ok","test",MB_OK);
}

然后通过隐式链接的方法
class _declspec(dllimport) CMyClass
{
public :
    void test();
};
CMyClass myclass;
myclass.test();
fengzi_zhu(★失业中....)你可以试试



Top

 回复人: Cool_jxx() ( ) 信誉:100  2003-3-26 15:02:35  得分:0



显式链接的话GetProcAddress()是不能得到函数指针的,



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-26 15:
16:37  得分:0



恩,有点道理,我试试.   显式连接应该不能得到..因为没有C的换名规则



Top

 回复人: Cool_jxx() ( ) 信誉:100  2003-3-26 15:23:35  得分:0



因为类的实例没有创建,没有分配内存.所以是得不到函数的指针的.
不知道显式链接通过何种方法??



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-26 15:
39:19  得分:0



要研究一下类信息存放在PE文件的那个地方,编译器是怎么对类申明处理的,以及
如何转变成汇编语言的。看来要另开一贴了。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-26 19:
57:37  得分:0



我顶~~~



Top

 回复人: JennyVenus() ( ) 信誉:151  2003-3-27 2:43:31  得分:0



up



Top

 回复人: qhluo02(*QHcsnd02) ( ) 信誉:100  2003-3-27 9:11:50  得分:0



up.....吧



Top

 回复人: yjy1129(阿宇) ( ) 信誉:100  2003-3-27 9:28:07  得分:0



great work,thanks!



Top

 回复人: rivershan(笨猫)(MS MVP)(寻觅爱情) ( ) 信誉:93  2003-3-27 9:
29:54  得分:0



............



Top

 回复人: dongjixianding() ( ) 信誉:100  2003-3-27 10:49:35  得分:0



DLL是Windows最重要的组成要素,Windows中的许多新功能、新特性都是通过DLL来

实现的,因此掌握它、应用它是非常重要的。其实Windows本身就是由许多的DLL组

成的,它最基本的三大组成模块Kernel、GDI和User 都是DLL,它所有的库模块也

设计成DLL。凡是以.DLL、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都

DLL,要是打开Windows\System目录,就可以看到许多的DLL模块。
尽管DLL在Ring3优先级下运行,仍是实现硬件接口的简便途径。DLL可以有自己的

据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式,减少了编程

设计上的不便;同时,一个DLL在内存中只有一个实例,使之能高效经济地使用内

存;DLL实现的代码封装性,使得程序简洁明晰;此外还有一个最大的特点,即
DLL
的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并

排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-27 12:
44:55  得分:0



大家都说说自己经验嘛!  遇到了某类问题,最后的解决方法.

             供大家学习学习啊.



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-28 8:
51:58  得分:0



再顶



Top

 回复人: dingzhw(叮当) ( ) 信誉:100  2003-3-28 9:27:23  得分:0



我想问大家,在DLL文件中调用另一个DLL文件该怎摸办?



Top

 回复人: konfyt(勇敢的心) ( ) 信誉:100  2003-3-28 9:38:08  得分:0



mark

我看到  dawn33(孤独的海) 这里了



Top

 回复人: okin() ( ) 信誉:100  2003-3-28 9:51:18  得分:0



mark it!



Top

 回复人: konfyt(勇敢的心) ( ) 信誉:100  2003-3-28 20:19:14  得分:0



赫赫,我看玩乐,制订



Top

 回复人: wos(tbye) ( ) 信誉:100  2003-3-28 21:54:40  得分:0



这端时间好忙,来报个到!^_^



Top

 回复人: magicblue(小飞侠) ( ) 信誉:100  2003-3-28 23:02:52  得分:0



Cool_jxx() :
你这个实际就是导出函数,namespace为CMyclass的test函数



Top

 回复人: farfh(远) ( ) 信誉:100  2003-3-29 5:39:40  得分:0



大家好啊,使用dll写com算不算啊?呵呵。
我顶!!!!!!!!!!!!!!!



Top

 回复人: bely_2000() ( ) 信誉:100  2003-3-29 6:55:42  得分:0



up



Top

 回复人: asalei(晓峰) ( ) 信誉:101  2003-3-29 9:00:31  得分:0



各位:

    如果只有dll  还有其中的类的说明   怎么调用其中的类和函数呢?



Top

 回复人: ypyao85(云) ( ) 信誉:101  2003-3-29 10:24:13  得分:0



up



Top

 回复人: SeekTruth(鹤舞白沙) ( ) 信誉:101  2003-3-29 10:41:48  得分:
0





  收藏+学习。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-29 13:
42:56  得分:0



上面都说了很多有关函数的痛惜,现在来看看DLL中使用的各种变量:
1。局部变量  函数中使用,在堆栈中分配

2。线程局部变量(TLS) 各函数间使用,也应该在每个线程的堆栈中吧!进程给
每个线程分配一定堆栈空间  每一个线程从进程处取得有64个索引槽的数组,使用
其中标记为INUSE的那个索引,通过
TlsSetValue()放入PVOID数据,我不知道该数据是怎么被处理的,是否存放在线程
堆栈中?

3。全局变量。进程中的各线程间共享,存放在数据节中(.data)该节的属性是
C0000040,即RW。

4。设定了“S”属性的自定义节中的变量。进程间共享,存放在自定义节中,该节
的属性为D0000040
   即RWS,“S”是“Shared" .
   实现方式:
   #pragma data_seg(".mydata")
   int s_nResult = 0;   //该变量进程间共享。
   ...
   #pragma data_seg()
   #pragma comment(linker, "/SECTION:.mydata, rws")
不过我有一下几个问题不解:
   1。当一个DLL已经在内存中的时候,进程A再去调用该DLL,那么就会将该DLL影
射到A的进程空间中,是否将所有的数据(包括.text的代码段.data的数据段.res
的资源段等)全部直接影射?如果是的话,那么数据段中的全局变量就是进程间共
享了。如果不是的话,数据段是否是直接COPY的?
我知道在内存中是将相同属性的数据放在一起的,那么是根据哪个属性来确定是影
射还是直接COPY的。哪位高手可以给我一个清楚的解释,谢谢了。。。。
  2。如果上面不是使用
   #pragma comment(linker, "/SECTION:.mydata, rws")
   那么.mydata节的属性好象是默认C0000040(RW),但是我后来加上这一句后并
没有改变属性。
   我将所有的工程相关文件全部删除,重新编译连接还是没有该变属性。但是我
在另一个工程中
   一开始就使用了上面的这一句预编译,生成的DLL文件中的.mydata节的属性是
D0000040(RWS)
  后来我试图该变该属性,也未能成功。  郁闷中....




Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-3-29 15:
30:36  得分:0



看来我要开一新贴了。



Top

 回复人: In355Hz(好象一条狗) ( ) 信誉:110  2003-3-29 16:03:42  得分:
0



1. WinNT/2000 应该是直接映射吧,映射的方式应该和节的属性有关。除了设置
shared 属性的节,都会以 PAGE_WRITECOPY / FILE_MAP_COPY 的方式映射到进程
 A ,因为 copy-on-write 机制,这些页面一旦修改就会创建自己的拷贝,非
shared 节的数据可以视为非共享的。

我印象中 Win9x 直接映射大部分节到相同的地址,然后将包含全局变量的节复制
一份以保证这些全局变量不被共享,这使得 Win9x 下 DLL 的 code 部分是共享的


2. 关注



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-1 12:
13:31  得分:0



up

接下帖:
http://expert.csdn.net/Expert/topic/1593/1593129.xml?temp=.9241602



Top

 回复人: yyan(海风) ( ) 信誉:100  2003-4-1 14:18:43  得分:0



up
gz




Top

 回复人: jiadrun(MustBeSuccess) ( ) 信誉:90  2003-4-1 15:41:59  得分:0




各有千秋,若谁能整理一下就好了。



Top

 回复人: fairychild(阿水) ( ) 信誉:100  2003-4-1 18:48:16  得分:0



gz







gz




Top

 回复人: fraidin(fraidin) ( ) 信誉:100  2003-4-2 9:51:51  得分:0



学习,要是能整理整理一下,就更好了。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-2 14:
18:30  得分:0



揭贴的时候就会整理的。 到是发篇文章。

可是都每人说说自己的经验,靠我一个人很难总结的。



Top

 回复人: codearts(代码艺术) ( ) 信誉:100  2003-4-2 21:23:23  得分:0



1.Win32DLL
      只能导出C函数和变量,但可以使用除CObject派生的类.
  不能在导出函数中建立对话框,因为不能进行模块环境转换.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
错:
   我就写了一个DLL中的对话框,不信我发给你看,留下E-Mail。

------------------------------------------------------------------
这说明可以在Win32DLL中导出对话框,我试过Win32DLL也是可以导出类的.现在就
要问了:
Win32DLL中不能用CObject的派生类?比如CWnd?



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-2 21:
33:26  得分:0



发到这个信箱zyfxyz@21cn.com 谢谢。
不知道你怎么搞的。我是没有实现。 我这里说的对话框不包括MessageBox哦~



Top

 回复人: xtmzl(我没钱!怎么办啊?) ( ) 信誉:100  2003-4-2 21:38:16  得分
:0



还有是dll的虚拟地址空间是在高端的2GB中。
且有用户模式和内核模式的dll。



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-3 16:
34:39  得分:0



EN



Top

 回复人: zhenxizhou(天上人间) ( ) 信誉:95  2003-4-3 16:43:22  得分:0




1、动态链接和静态链接
链接是指将函数调用与相应的函数体代码彼此关联的过程,若此过程在程序开始运
行前的编译阶段完成,称为静态链接。在程序运行时进行的链接方式称为动态链接
。一般说来,动态链接是通过函数指针来实现。由于虚函数的函数名、返回类型和
参数类型完全相同,但函数体不同,因此在编译阶段无法确定函数调用与哪个函数
体相关联,只能由系统在程序运行时确定。
2、动态链接库
Windows操作系统使用动态链接库(DLL)来支持公共函数的调用。动态链接库是一个
包含函数的库文件。它与类的区别在于类是创建时的模块,而动态链接库是运行时
的模块。当用户创建使用动态链接库的应用程序时,必须将动态链接库文件和应用
程序的可执行文件一同分发。当应用程序开始执行时,需要寻找与它链接的DLL库
,并把该DLL映射到进程的内存空间。Windows将按下列顺序来搜索DLL:
包含EXE文件运行的目录;
进程的当前目录;
Windows的SYSTEM子目录;
Windows目录
在Path环境变量中所指目录。
3、函数的导入和导出
在使用动态链接库时,首先,必须导出包含在DLL内将被DLL外部调用的所有函数。
其次,为了使用包含在DLL中的函数,必须将其导入。使用C\C++时,导出操作是通
过使用dllexport关键字来完成的,导入操作是通过使用dllimport来完成的。
dllexport和dllimport是VC支持的扩展关键字。DLL中的函数必须由使用它们的应
用程序导入,用户必须在与DLL相联系的DEF文件的EXPORTS部分中指定从DLL中导出
的函数。尽管可以使用上述操作来完成函数的导出,但dllexport提供了更方便的
方法。dllexport和dllimport不能单独使用,在前面必须有另一个扩展关键字
_declspec,如:_declspec (dllexport) void Func(int a)。如果使用了C++,编译
器会根据类名、函数名和参数类型为Func产生一个其他语言不能使用的修饰符,它
们在工程的MAP文件中列出。如果希望使用普通名Func,则须如此声明:extern “
C” __declspec (dllexport) void Func(int a)。为了简化说明导入和导出函数
的语句,可创建宏:#define DllExport _declspec (dllexport)。这样就可:
DllExport void Func(int a)
要连接到一个DLL,仅仅有导入声明还不够。必须为连接器指定导入库(LIB),而且
程序必须实际调用了DLL的导出函数中的至少一个函数。
4、隐式链接和显式链接
上面说的动态链接库的隐式链接,是C++中DLL的常用方式。当创建一个DLL时,连
接器产生一个附加的导入LIB文件,其中包含了每个DLL的导出符号和(可选)序号,
但没有代码。LIB是DLL的一个代理,它被加到客户程序的工程中。当创建客户(静
态链接)时,导入的符号被匹配到LIB文件的导出符号,这些符号(或序号)被绑进
EXE文件里。LIB文件也包含了DLL文件名(但不是全路径名),文件名也被保存到
EXE文件里。当客户转载后,Windows找到了DLL并进行装载,然后根据符号或序号
动态链接。
显式连接并不需要导入文件,而是调用Win32的LoadLibrary函数,指定DLL的路径
名作为参数。LoadLibrary返回一个HINSTANCE参数,可以在GetProcAddress调用中
使用该参数,该调用把一个符号(或序号)转换到DLL中的地址。对于解释语言更为
合适。
对于隐式链接,所有的DLL都在客户装载的时候被装载,但在显式链接时可以决定
什么时候装载和卸载。显式链接允许在运行时决定装载哪个DLL。
5、扩展DLL和正规DLL
应用程序向导可以创建MFC库支持的两种DLL:扩展DLL和正规DLL。
扩展DLL支持C++接口,可以导出整个类,可以构造这些类的对象或从这些类进行派
生。扩展DLL动态链接到MFC库,并且客户程序和扩展DLL要一致链接到MFC DLL的相
同版本(mfc42.dll、mfcd42.dll等)。在创建扩展DLL时,必须把宏AFX_EXT_CLASS
加到类声明中。
如果需要一个DLL可被任何Win32编程环境(包括VB)装载,必须使用正规DLL。正规
DLL可以导出C风格的函数,但不能导出C++类、成员函数或重载函数,因为每一个
C++编译器都有其自己修饰名字的方法。但可在正规DLL内部使用C++类(特别是MFC
类)。
当创建MFC正规DLL时,可以选择静态链接或动态链接到MFC库。静态链接时,DLL将
包括所有它需要的MFC库代码的拷贝,可独立于MFC库。如果选择动态链接,必须保
证适当的MFC DLL在目标机器上存在。
在应用程序向导产生正规DLL时,只要编写C函数,然后用_declspec(dllexport)修
饰符导出这些函数(或者在工程的DEF文件里加入函数入口)。为了解决一个正规
DLL调用mfc42.dll时全局变量不同步的问题,需要在正规DLL所有导出函数的开始
处插入下面代码:AFX_MANAGE_STATE(AfxGetStaticModuleState())。如果MFC代码
被静态链接,则该宏不会有任何影响。




Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-3 16:
54:35  得分:0



楼上的大哥,好象有人贴过了。呵呵~ 想抢分我另开帖给你啊~ :D



Top

 回复人: microsoftwin(流星雨点) ( ) 信誉:100  2003-4-3 16:55:28  得分
:0



高手如云




Top

 回复人: COOL099(Alan Zjou) ( ) 信誉:100  2003-4-3 17:23:21  得分:0



在常規DLL中調用DLL用一個例子。(受TRACE啟發)
#include "stdafx.h"
#include "maindialog.h"
class CTracerDLL : public CWinApp
{
public:
        virtual BOOL InitInstance(); // Initialization
        virtual int ExitInstance();  // Termination (WEP-like code)
        // nothing special for the constructor
        CTracerDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
};

BOOL CTracerDLL::InitInstance()
{
        // any DLL initialization goes here
        TRACE0("TRACE.DLL initializing\n");
        return TRUE;
}

int CTracerDLL::ExitInstance()
{
        // any DLL termination goes here (WEP-like code)
        return CWinApp::ExitInstance();
}

extern "C" BOOL FAR PASCAL EXPORT FilterDllMsg(LPMSG lpMsg)
{
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
        TRY
        {
                return AfxGetThread()->PreTranslateMessage(lpMsg);
        }
        END_TRY
        return FALSE;
}

extern "C" void  _stdcall   ShowMain()
{
        CMainDialog dlg;
        dlg.DoModal();
}

CTracerDLL  NEAR tracerDLL(_T("trace.dll"));

導入此DLL後就可用ShowMain方法顯示出對話框。



Top

 回复人: psusong(爱因思念) ( ) 信誉:120  2003-4-4 23:26:22  得分:0



路过



Top

 回复人: happyandy(安迪) ( ) 信誉:100  2003-4-5 15:15:36  得分:0



我都看晕了,说的好麻烦呀!各位能不能用简短的语言描述同时用示例说明,我想
这样学起来速度就快了吧!(声明:我可不是在偷懒!)^_^



Top

 回复人: jhyu(阎罗大王把小不死炸死了) ( ) 信誉:100  2003-4-5 15:51:08
 得分:0



把“windows核心编程”最后一部分看懂就行啦



Top

 回复人: webber84(***闭关修炼中***) ( ) 信誉:105  2003-4-5 17:06:35
得分:0



第二个问题倒是挺奇怪的,你的#pragma放在什么地方啊? 不会是stdafx.h吧。



Top

 回复人: o_racle(璐璐) ( ) 信誉:101  2003-4-5 20:05:11  得分:0



该说得都说了



Top

 回复人: zhenxizhou(天上人间) ( ) 信誉:95  2003-4-5 21:50:05  得分:0




哎!把自己的笔记贴出来却被认为是抢分。
好郁闷啊。



Top

 回复人: freeboy20sui(行云流水) ( ) 信誉:100  2003-4-6 17:39:01  得分
:0



up



Top

 回复人: nonocast(如果你信仰光明,那是因为到处都是黑暗!) ( ) 信誉:97
 2003-4-7 6:58:19  得分:0



哎!把自己的笔记贴出来却被认为是抢分。
好郁闷啊。

扫饿!



Top

 回复人: myelan(myelan) ( ) 信誉:100  2003-4-7 13:59:01  得分:0



我觉得在这个帖子里面也应该有其他语言调用DLL的内容,

想请教一下,java可不可以调用DLL,需要注意什么问题?
或者,vc可不可以调用java的package?



Top

 回复人: wenddy112(敬) ( ) 信誉:100  2003-4-7 17:17:41  得分:0



up,up,up!



Top

 回复人: smiles() ( ) 信誉:100  2003-4-8 22:27:40  得分:0



我在导出函数中间接调用WINSOCK.H中定义的函数,如SELECT,RECV,SEND等,总会
报错:execute.obj : error LNK2019: unresolved external symbol _select@20
 referenced in function "int __stdcall testSocket(int)"
(?testSocket@@YGHH@Z)导出函数定义如下:extern"C" __declspec(dllexport)
int  _connectServerForUpload(char *serverid,int port,char *username,char
 *password,bool & IncreFlag)
这是怎么回事?



Top

 回复人: ksyou(过河卒:不能回头怎么办?) ( ) 信誉:100  2003-4-9 16:
30:53  得分:0



收藏,学习



Top

 回复人: tudou614(土豆) ( ) 信誉:100  2003-4-10 10:53:12  得分:0



建议大家上去看看啊
很有帮助的
我不是骗人
我知道的一个网址
/////////////////////////////////////
http://www.ittide.com/



Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-4-21 10:
56:39  得分:0



最近很忙没时间上了。哎,看看51有时间再整理整理吧。抱歉了



Top

 回复人: yaven365(天涯网客) ( ) 信誉:100  2003-4-25 15:02:09  得分:0




用VC++5.0制作DLL经验一二

作者:周志杰


本文'一'、'二'两部分适用于对DLL的基本制作方法已经了解,或手头有关于DLL
制作方法的书籍的读者.对于初次接触DLL制作的读者,建议您先按'三'中的步骤
建立一个自己的DLL并在另一个应用程序中成功的调用它之后再阅读'一'、'二'.

---- DLL可以分为两个不同的类别:用C/C++(不用对象)编写的基于API的传统DLL
和基于MFC对象的DLL.

一.两种类型的比较:
---- 1. 基于MFC的DLL限制在使用MFC的编译器中.
---- 基于API的DLL可以从一种编译器移植到另一种编译器.

---- 2. 基于MFC的DLL可以由制作向导构建框架,制作简单

---- 基于API的DLL的制作向导只为你制作了一个空的DLL工程,工程的维护和代
码的编写全部需要手工完成(这一点在VC 6.0中有了改进)

---- 3. 基于MFC的DLL不适用与制作读取二进制文件的DLL

---- (无法正确读取与DOS应用程序共享的二进制文件)

---- 基于API的DLL可以正确读取在DOS环境中创建的二进制文件.

---- 造成该结果的原因其实很简单:

---- 在读取二进制文件的过程中通常会使用"结构(体)",基于MFC的DLL要加载
MFC,它要求"结构成员位对齐"的比特位是8位,而且你无法方便的通过选中
"Project- >Setting- >C/C++"选项卡中的"Code Generation"再修改
"Struct member alignment"来使其变为1位(在VC5.0中即使改变了,在编译时
该改变也会被忽略.不过这一不足在VC6.0中已经得到了改进,读者有兴趣的话可
参见笔者《在VC6.0中读取二进制文件的惊喜》一文).

---- 而基于API的DLL则可以通过以上的方法方便的实现.

二.在实际制作与使用中的一点经验:
---- 1.制作DLL的目的之一是共享资源/代码.所谓"共享"当然不应该仅仅是几个
VC++制作的应用程序可以使用,但是在与其他编程语言协作时,有些问题是需要注
意的.
---- 在制作DLL时,VC++对函数的省缺声明是"__cedcl",也就是说,如果你在声
明你的函数时不作特殊声明的话,你制作的DLL将只能被C/C++调用,如果你想用
其他开发语言(比如VB5.0)调用它就会报错,即使调用方法完全正确.

---- 那么该怎么办呢,你一定已经猜到了---不要用省缺的声明方式---一个很
好的选择是使用"WINAPI"来声明你的函数.它可以把你的DLL中的函数声明成
WINDOWS API供其他程序调用(当然也包括C/C++制作的程序).

---- 2.建议你在制作DLL的同时制作包括导出函数原型声明的.H文件虽然这不
是必须的但是若你的DLL是被C/C++调用,.H文件和.LIB文件可以为使用你的DLL的
开发人员省去不少精力,当你需要修改/升级你的DLL时更是如此.DLL的C/C++使用
者只要在工程中引入.H和.LIB文件可以象使用自己编写的函数一样方便的使用
DLL中的函数,不必再使用存储DLL句柄、声明函数型指针、LoadLibrary、
GetProcAddress那样繁复的调用方式.

---- 3.虽然你不必编写.DEF文件就能制作出基于API的.DLL文件.但是制作.DEF文

件并不难,至少你有捷径可以走.有一个很简单的方法你不妨一试:

---- 例如,你用基于API的方法制作了一个DLL工程文件并为其编写了.CPP和.H文
件,你可以保存并关闭该工程,然后在另一个目录中创建一个与其同名的基于MFC的

DLL工程.好了,现在你已经知道怎么做了---将该目录中的.DEF文件移动过去就可
以了.省下的工作就是再次打开基于API的DLL工程,并将.DEF文件加入工程,将你的

导出函数的函数名加到EXPORTS之后,再重新编译工程就OK了.

---- 4.DLL文件的省缺名称是与工程名一致的(也是在.DEF文件中LIBRARY 之后
的名字),不要试图在制作完毕之后通过简单的修改.DLL文件的文件名来改变它,
这会导致使用该DLL的应用程序错误.

三.一个例子:
---- DLL中定义有两种函数:
---- 导出函数(exportfunction): 可以被其他模块调用
---- 内部函数(internalfunction): 只能在DLL内部使用
---- 创建一个基于API的DLL.本例只定义了导出函数.

---- 1.在FILE- >NEW- >PROJECTS中选择"WIN32 Dynamic-Link Library"在
Project Name中输入 "a"按OK

---- 2.在FILE- >NEW- >FILES中选择C++ SOURCE FILE,在FILE中输入a.cpp,
按OK

---- 在FILE- >NEW- >FILES中选择TEXT文件,在FILE中输入a.h,按OK

---- 在FILE- >NEW- >FILES中选择TEXT文件,在FILE中输入a.def,按OK

---- 3.源文件:

        //---------------------------
        //a.cpp
        #include < windows >
        WINAPI int add(int a,int b)
        {       return (a+b);
        }
        //---------------------------
        //a.h
        WINAPI int add(int a,int b);
        //---------------------------
        //a.def
        LIBRARY      "aaa"      ;指出DLL的名字
        DESCRIPTION  'aaa Windows Dynamic Link Library'
        ;描述DLL的用途(此句可选)
        EXPORTS      add        ;导出函数的名字

四.调用DLL的方法:
---- 1.通常我们在调用DLL时所需的DLL文件必须位于以下三个目录之一:
---- (1)Windows的系统目录:\windows\system;

---- (2)DOS中path所指出的任何目录;

---- (3)程序所在的目录;

---- 同时应注意管理好你的.lib文件和.h和文件

---- 2.建立一个工程,简单起见可建立一个控制台应用程序.

---- 3.在工程中引入a.lib:

---- (1)如果你的a.lib放在VC标准的LIB文件夹中.

   单击Project- >Project Settings...
   在link选卡的object/library modules中加上a.lib即可

---- (2)如果你的a.lib不是放在VC标准的LIB文件夹中
   单击Project- >Add to Project- >files...
   找到a.lib文件,按OK
< pre >
4.//------------------------
          //call_a.cpp
          #include< stdio.h >
          #include "c:/a/a.h"
          void main(void)
          {     int c=0;

                c=add(1,2);
                printf("1+2=%d",c);
          }
        //本程序在VC5.0下调试通过





Top

 回复人: vagilearbor(arbor) ( ) 信誉:100  2003-4-25 15:24:50  得分:0




MFC常规型动态联结库建立方法:

1。建立工程(名字为ReguDll)
2.在ReguDll.h中加入代码:
        #define DllExport _declspec(dllexport)
        extern "C" DllExport float MyFunction(float f1,float f2);

3.在ReguDll.cpp中加入函数代码:
        extern "C" DllExport float myfunction(float f1,float f2)
        {
        //add your code here

        }
4.编译生成*.dll文件。


使用dll方法:
   建立工程(名字test)
   1.把得到的*.dll和*.lib文件放入这个工程下面,再把*.lib文件加入这工程;

   2。在testDlg.h中加入代码:
      #define DllImport _declspec(dllimport)
      extern "C" DllImport float myfunction(float f1,float f2);
   3.在testDlg.cpp中激发调用的函数中加入代码:
      直接调用就可以了。如:
      float x1,x2,sum;
      x1=2;x2=3;
      sum=MyFunction(x1,x2);
      ....



 这样就完成了!



Top

 回复人: strongerman(猛男) ( ) 信誉:100  2003-4-25 15:42:41  得分:0



up



Top

 回复人: weijiechen(SUMMER) ( ) 信誉:100  2003-4-25 23:52:12  得分:0




真是太好了



Top

 回复人: unicornstudio(unicorn) ( ) 信誉:100  2003-4-26 0:46:26  得分
:0



up



Top

 回复人: diabloqin(fuckmachine) ( ) 信誉:100  2003-4-26 10:37:12  得分
:0



mark



Top

 回复人: sunnylee2k() ( ) 信誉:100  2003-4-26 11:07:22  得分:0



感谢大家



Top

 回复人: sjd163(sjd163) ( ) 信誉:100  2003-5-3 21:12:59  得分:0



有感于大家的追求精神。



Top

 回复人: unicornstudio(unicorn) ( ) 信誉:100  2003-5-3 21:49:47  得分
:0



up



Top

 回复人: mymmsc(拉灯) ( ) 信誉:100  2003-5-4 8:21:06  得分:0



我来学习一下。



Top

 回复人: eulerLCS(阿童木) ( ) 信誉:100  2003-5-8 13:12:09  得分:0



.



Top

 回复人: Behard(我爱天安门) ( ) 信誉:100  2003-05-11 03:15:00  得分:
0


  其实我觉得 Win32Dll 也是可以制作对话框的
不过要自己写
其实只要 SDK 可以实现的,Win32Dll 都可以实现


Top

 回复人: sunny6281(Sunny) ( ) 信誉:100  2003-05-12 17:54:00  得分:0


  能不能详细解释一下如何调用DLL?
显式,隐式

谢谢


Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-05-12
18:11:00  得分:0


  显示调用:
1.申明一个和DLL某导出函数相同类型的函数指针
2.用LoadLibrary(...)载入该DLL
3.使用GetProcAddress()取得需要的导出函数指针
4.可以使用该指针了
隐式调用:
1.include 某DLL的头文件
2.#program commment(lib, "mou.dll");连接某DLL库



Top

 回复人: danielxuao(单单) ( ) 信誉:100  2003-05-12 18:25:00  得分:0


  hook


Top

 回复人: TwjgoTwjgo(C语言爱好者) ( ) 信誉:98  2003-05-13 23:17:00  得
分:0


  dawn33(孤独的海)
你好,
{
           DLL_PROCESS_ATTACH: 进程被调用;
           DLL_THREAD_ATTACH: 线程被调用;
           DLL_PROCESS_DETACH: 进程被停止;
           DLL_THREAD_DETACH: 线程被停止;
}
???????
进程能掉用DLL吗?(你是说的。。这个进程的主线程吗?)

请回答?

调用约定(Calling convention):决定函数参数传送时入栈和出栈的顺序,由调用
者还是被调用者把参数弹出栈,以及编译器用来识别函数名字的修饰约定。


      请写的详细一点!(决定函数参数传送时入栈和出栈的顺序)???









Top

 回复人: Tiga(我要学习) ( ) 信誉:100  2003-05-15 11:14:00  得分:0


  good


Top

 回复人: nforcedzh(翔天) ( ) 信誉:100  2003-05-15 15:29:00  得分:0


  dll是用VC写的,我想问怎样在vb中调试这个dll。编译成exe后,可以运行dll。
没有编译以前,是不能调用dll的,请问这是什么原因?
把dll放到系统文件夹下,也不能调试dll,提示"调用约定错误"。而编译以后,就
没有提示,可以正常运行,不知道什么原因?


Top

 回复人: fengzi_zhu(才知道自己还是初学者) ( ) 信誉:100  2003-05-15
15:43:00  得分:0


  VB中调用DLL我不知道,不过看看下面连接:
http://asp.6to23.com/nowcan/tech/kbtrc.htm
或许会有帮助


Top









【 在 tanher (平纳川) 的大作中提到: 】
: 【 以下文字转载自 Virus 讨论区 】
: 【 原文由 tanher 所发表 】
:          谢谢!!!!


--
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 61.144.235.40]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店