首页
社区
课程
招聘
[原创]改造VB6,使其支持生成具有输出函数的dll
发表于: 2006-12-31 02:19 9450

[原创]改造VB6,使其支持生成具有输出函数的dll

2006-12-31 02:19
9450

【文章标题】: 改造VB6,使其支持生成具有输出函数的dll
【文章作者】: edisonH
【作者邮箱】: edison_h_cr@yahoo.com.cn
【软件名称】: VB 6.0
【下载地址】: 自己搜索下载
【编写语言】: VB 6.0
【操作平台】: WindowsXP sp1
【作者声明】: 没有什么技术,失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
    使用VB6创建dll时,可选项为“ActiveX Dll”,这种dll只是com组件,不支持在dll中输出函数。其实VB生成最终的exe或dll目标文件是这样的:首先生成obj文件,然后调用link.exe链接成最终的exe或dll,然后删除obj。
    网上很早就有人提出一种方法:将原来的link改名(如orgLink),然后写一个自己的link.exe,再去调用原来的link,如下
  Private Sub Form_Load()
      If (MsgBox("继续链接", vbOKCancel) = vbOK) Then
          Shell "orgLink.exe " & Command
      End If
      End
  End Sub
当MsgBox中断下来的时,把相关的obj文件拷出来,然后增加/EXPORT 开关手动链接来增加输出函数。
  
    假设VB装在"F:\Program Files\VB6\"下
    源码保存在"F:\Program Files\VB6\Project\TestDll\"下

我们看看VB自己链接时的链接代码是怎么样的,如下:

"F:\Program Files\VB6\Project\TestDll\Class1.OBJ" "F:\ProgramFiles\VB6\Project\TestDll\Module1.OBJ" "F:\Program Files\VB6\Project\TestDll\TestDll.OBJ" "F:\Program Files\VB6\VBAEXE6.LIB" /ENTRY:__vbaS /OUT:"F:\Program Files\VB6\Project\TestDll\TestDll.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /DLL  /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078
  
那么增加/EXPORT 开关来增加输出函数的链接代码如下:

"F:\Program Files\VB6\Project\TestDll\Class1.OBJ" "F:\ProgramFiles\VB6\Project\TestDll\Module1.OBJ" "F:\Program Files\VB6\Project\TestDll\TestDll.OBJ" "F:\Program Files\VB6\VBAEXE6.LIB" /ENTRY:__vbaS /EXPORT:TestFunction /OUT:"F:\Program Files\VB6\Project\TestDll\TestDll.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /DLL  /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078
  
可以看到上面链接命令中通过/EXPORT 开关增加了输出函数TestFunction。
  
  
    但是手动链接比较麻烦,而通过/EXPORT 开关来编写可以增加输出函数的自动链接也不太方便。还好,link还有另一个开关可以批量增加输出函数--/DEF,可以这样使用:/DEF:"...\TestDll.def",

其中输出函数需要放到dll定义文件dll.def中,如下:
  
  LIBRARY   TestDll
  EXPORTS   TestFunction
  
LIBRARY 关键字是必须的,它定义了DLL的模块名称,必须和动态链接库的名称相同。
EXPORTS 关键字告诉链接器该DLL的输出函数,多个输出函数时可以重复使用关键字,如
  LIBRARY   TestDll
  EXPORTS   TestFunction0
  EXPORTS   TestFunction1
  EXPORTS   TestFunction2
......
  
    这下明朗了,可以在源码目录下增加一个DLL.def文件(如果没有保存就生成目标dll,可将dll.def放在目标目录下),里面用关键字EXPORTS定义需要输出哪些函数,再通过/DEF开关来告诉链接器.

链接代码如下:
"F:\Program Files\VB6\Project\TestDll\Class1.OBJ" "F:\ProgramFiles\VB6\Project\TestDll\Module1.OBJ" "F:\Program Files\VB6\Project\TestDll\TestDll.OBJ" "F:\Program Files\VB6\VBAEXE6.LIB" /ENTRY:__vbaS /OUT:"F:\Program Files\VB6\Project\TestDll\TestDll.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /DLL /DEF:"F:\Program Files\VB6\Project\TestDll\DLL.def"  /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078
  
    下面是一个完成上述工作的VB代码,把原来的link.exe改为orgLink.exe,下面代码生成为link.exe即可
  
  Private Sub Form_Load()
  
  Dim sCmdLine$, s1$, s2$,s3$,s4$, n1%, n2%, n3%, n4%
  
  sCmdLine = Command
  
  n1 = InStr(sCmdLine, "/DLL")   ' 查找/DLL开关,确定目标文件是dll才决定是否增加输出函数
  
  If n1 = 0 Then                 ' 目标文件是exe就直接调用orgLink
  Shell "orgLink.exe " & Command
  End
  End If
  
  n2 = InStr(sCmdLine, ".OBJ")   ' 取DLL.def的目录。它与Class1.OBJ同一目录,所以取Class1.OBJ目录即可
  s1 = Left(sCmdLine, n2 - 1)
  n3 = Len(s1)
  s2 = StrReverse(s1)
  n4 = InStr(s2, "\")
  s3 = Left(s1, n3 - n4 + 1)
  
  s4 = " /DEF:" & s3 & "DLL.def" & Chr(&H22)  ' /DEF:"F:\Program Files\VB6\Project\TestDll\DLL.def"
  
  sCmdLine = sCmdLine  & s4      ' 为方便起见,直接将/DEF:"...\DLL.def"插到命令行最后,不影响结果
  
  Shell "orgLink.exe " & sCmdLine
  
  End
  End Sub
      
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                      2006年12月31日 2:05:33


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (13)
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
放一个编译版
上传的附件:
2006-12-31 11:59
0
雪    币: 223
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
收藏一下,我在网上见过好几个,不过你的这个最详细了
2007-1-5 10:10
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
方法不错。谢谢!
2007-1-9 13:49
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
本工具的所有均来自网络,理当回归网络

一、如何使用标准DLL编译工具

使用方法很简单。首先,将C:\Program Files\Microsoft Visual Studio\VB98\link.exe改名为link2.exe
其次,将本文件link.exe复制到C:\Program Files\Microsoft Visual Studio\VB98文件夹中即可。

本工具让你即可使用VB6原默认方式编译,也可编译WINDOWS标准DLL。

二、如何用VB6生成WINDOWS标准DLL

说明:以下内容源自Iczelion的Win32汇编教程中“动态链接库”一节,有改动。
(原文请见罗云彬汇编网站http://211.90.241.130:22366/list.asp?part1=1&part2=4)

对WINDOWS标准DLL而言,每一个DLL必须有一个入口点函数,WINDOWS每一次在做下面的动作时会调用该入口点函数:

        当动态链接库被加载时
        当动态链接库卸载时
        同一进程的线程生成时
        同一进程的线程退出时

入口点函数的名称无所谓,在VB6中,我们姑且作如下定义

Const DLL_PROCESS_DETACH=0 '动态链接库从进程的地址空间卸出时
Const DLL_PROCESS_ATTACH=1 '动态链接库第一次插入进程的地址空间时
Const DLL_THREAD_ATTACH=2 '新线程生成
Const DLL_THREAD_DETACH=3 '线程销毁

Function DllEntry(ByVal hInstDLL As Long, ByVal reason As Long, ByVal reserved As Long) As Long
    Select Case reason
        Case DLL_PROCESS_ATTACH
            'MsgBox "动态链接库第一次插入进程的地址空间"
            DllEntry = 1
        Case DLL_PROCESS_ATTACH
            'MsgBox "动态链接库从进程的地址空间卸出"
            DllEntry = 0
        Case DLL_THREAD_ATTACH
            'MsgBox "新线程生成"
            DllEntry = 1
        Case DLL_THREAD_DETACH
            'MsgBox "线程销毁"
            DllEntry = 0
    End Select
End Function

该入口函数DllEntry共有三个参数:hInstDLL, reason, reserved,只有前面两个是重要的。
hInstDLL:是该动态链接库模块的句柄。它和进程的实例句柄不一样。如果您以后要用,可以保存它,因为以后再要获得它不容易。
reason:根据不同的时机,传入的值可能是下面的四个值中的一个:

        DLL_PROCESS_ATTACH 动态链接库第一次插入进程的地址空间时。当传入的参数是该值时,您可以做一些初始化的工作。
        DLL_PROCESS_DETACH 动态链接库从进程的地址空间卸出时。您可以在此做一些清理的工作。譬如:释放内存等。
        DLL_THREAD_ATTACH  新线程生成。
        DLL_THREAD_DETACH  线程销毁。

如果想要库中的代码继续执行,返回TRUE,否则返回FALSE,那样动态链接库就不会加载了。譬如:您想分配一块内存,如果不成功的话就退出,这时您就可以返回FALSE。那样动态链接库就不会加载了。
您可以加入的函数,它们的位置并不重要,把它们放在入口点函数的前面或后面都可以。只是如果您想要它们能被其它的程序调用的话,就必须把它们的名字放到模块定义文件(.def)中去。

模块定义文件.def,将由本工具自动为您生成,而无须您的干预。
2007-1-11 13:23
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
晕啊,无权上传附件...
2007-1-11 13:37
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
需要者可留下妹儿...
2007-1-11 13:42
0
雪    币: 481
活跃值: (2734)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
8
可以将工具上传到这里:http://999kb.com/
2007-1-12 14:49
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
http://mumayi1.999kb.com/pic/2007-01-12/fnw50si4llua3tnb82us.zip
2007-1-12 15:17
0
雪    币: 481
活跃值: (2734)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
10
楼上提供的工具不错,很方便.谢谢.
2007-1-13 00:37
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
问一下,这样编译的dll是否是线程安全的?
2007-1-13 21:08
0
雪    币: 1580
活跃值: (72)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
试了一下,编译过程中弹出加载DLL错误!
win2000 server!
2007-1-18 09:10
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
工具提供的是源码和样例,而且是绿色的

DLL加载问题应该是你的系统环境本身的问题
2007-1-18 10:58
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
以前用VB写程序的时候用过这种方法,是在台湾的一个网站上看到的,后来在SourceForge上看到新出了一个fbc,就是FreeBASIC Compiler,后来就用fbc写了
2007-1-20 11:32
0
游客
登录 | 注册 方可回帖
返回
//