添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

前段时间,同学接了一个项目,在网页上显示autoCAD的图。在做项目的过程中,遇到一个棘手的问题。在使用vb语言开发的第三方插件中,有一个函数是地址传值的方式传参。想在js中调用该函数,但是,js不支持类似指针的概念。后来在网上百度,发现可以使用dll封装的方式解决该问题。即 把这个ocx(插件)用Activex封装一层。 JavaScript –> ActiveX –> 第三方ocx 做一个ActiveX来调用第三方ocx,给它来个引用传递就行了。详见: http://blog.sina.com.cn/s/blog_704d0c1c0100mft7.html

在制作该dll的过程中,遇到了很多问题。开发环境为vb。首先打开vb,选择新建AvtiveX dll。在出来的界面中编写代码。

dll是一个函数库,他不能独立运行,没有main函数。但是dll有一个dllMain函数,该该函数即为该dll的入口函数。如果缺少该入口函数,那么该dll在加载的时候即会报”找不到入口点

dllRegisterServer“的错误。

Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Boolean
Select Case fdwReason
Case DLL_PROCESS_DETACH
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH
Case DLL_THREAD_DETACH
End Select
End Function

在添加了dllMain入口函数后,又出现了问题,即在调用dll中的函数时在js报“对象不支持此属性或方法的错误”。经过一番调试,找到了错误所在,DllMain函数没有处理线程加载的情况。修改DllMain函数

Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Boolean
Select Case fdwReason
Case DLL_PROCESS_DETACH
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH

DllMain=True

Case DLL_THREAD_DETACH
End Select
End Function

QQ 594363468

DLL 文件(即 Dynamic Link Library ,动态链接库)作为系统的一个重要的组成部分,除了一些小程序外,我们几乎能在所有软件中看到 DLL 文件,而且如果使用 VB 写的一些收费软件有一个 DLL 代替关键函数,想破解都难了。因此,我们就有必要来学习如何编写 DLL

对于很多初学 VB 的网友来说, VB 是一门比较简单的语言,而 MicroSoft 公司在开发 VB 时,也增添了很多功能。所以,我个人觉得 VB 除了部分不足之外还是挺不错的,当然我指的不足是主要是 VB 运行库方面的问题。

对于很多 VB 初学者来说,都会有这么一个错误的认识—— VB 中创建的 DLL 只是 COM 组件,无法作为输出函数的 DLL (即 VB 写的 DLL 是不完整的 DLL )。然而,对于一些 VB 的高手来说 , 他们就知道应该如何写具有返回值的 DLL 。其实,国外早已经有人做出了在 VB 中制作标准 DLL Add-Ins 了,而且在网上也有对于写 VB 创建能作为输出函数的 DLL 的相关文章。今天,我再来讲讲这个话题—— VB 创建能作为输出函数的 DLL

对于 VB 编写 DLL ,按照我的经验,主要分为两步:一、“安内”,二、“攘外”

首先,“攘外必先安内”

我们要知道如何使 DLL 拥有一个能被调用的 API 函数。很简单,我不想多说,就是在 Module 里面写一个 Public Function

接下来,我们就可以“攘外”了

那么,先来介绍一下编译技术

编译器的编译技术可以分为 Native Compile (自然编译)与 P-Code Compile (伪编译)两种。

自然编译是编译器将高级语言转换为汇编代码,并经链接生成 EXE 程序的过程。

伪编译是编译器将高级语言转换为某种编码后,将能解释、执行此编码的一段程序一同链接,生成 EXE 程序。

伪代码 P-Code ,最早应该叫做 Pascal-Code ,其名称起源于一个 Pascal 编译器使用的“中间代码”编译技术。现在一般作为 Pseudo-code (伪代码)或 Packed-code (压缩代码)简称。

采用伪代码编译时,每个 VB 源文件(包括 .frm (窗体)、 .bas (标准模块)、 .cls (类模块))经 VB IDE 编译后各自生成相应的 .obj 文件,交链接程序 Link.exe 生成伪编译的可执行文件( EXE DLL OCX 等)。

而用自然编译时,每个 VB 源文件由 C2.exe 编译生成汇编代码,生成相应的 obj 文件,再由 Link.exe 链接成为完整的可执行文件。

别看编译只有两步,其实,有大玄奥在里头。。。

MicroSoft 公司,可以说是十分的狡猾,因为在默认的方式下, VB 编译的两步使用到的命令行都是他们设定好的,所以,跳过了很多有用的部分,包括我们今天讲的输出函数部分。如果在 LINK 的时候添加 EXPORT 选项,实际上是可以输出函数的。但是,在 VBLinkd 的命令行中将这个选项部分跳过了。而且过分的是: VB 在构造 EXE 后会将编译出来的 OBJ 文件删除,这样就无法手动通过 Link 来创建我们需要的 DLL 了。

根据前人的方法,加上自己修改,用一个比较龌龊的方法来变通

打开“ VB6.0 ”,新建一个“标准 EXE 工程”,把 Form 移除,添加一个 Module

在模块里输入一下代码:

Sub Main()

If Command = "" Then Exit Sub ' 命令行不为空

Dim intCMD As Integer

'Clipboard.Clear ' 清空剪贴板

'Clipboard.SetText Command ' 将命令行复制到剪贴板

' 去掉 复制到剪贴板 LINK 速度会快些

intCMD = MsgBox(" 编译命令行如下 :" & vbCrLf & Command & vbCrLf & " 点击“是”继续编译,点击“否”编译 DLL ,点击“取消”中断编译 ", vbYesNoCancel + vbInformation, " 编译 ")

Select Case intCMD

Case vbYes ' 选择“是” 继续编译

Shell "VBLINK " & Command, vbHide

Case vbNo ' 选择“否”

Dim FuncName As String, cmd As String, l As Integer

FuncName = InputBox(" 请输入 输出的函数名称 ( 对个函数 请用英文半角分号“ ; ”分开 )", _

" 非法操作出错我不管 ") ' 模块内能编译出来的输出函数名

' 修改命令行

If FuncName = "" Then Exit Sub

FuncName = Replace(FuncName, ";", " /EXPORT:")

Loop Until 0 = InStr(FuncName, ";")

l = InStr(Command, "vbaS")

cmd = Left(Command, l + 4) & "/EXPORT:" & FuncName & Right(Command, Len(Command) - l - 3)

Shell "VBLINK " & cmd, vbHide

Case vbCancel ' 中断编译

Exit Sub

End Select

End Sub

' 大家可能看出来了 , 没错  就是在每个输出函数前加 /EXPORT:

生成 MyLink.exe ,复制到 VB 的安装文件夹里,把安装文件夹的 LINK.EXE 改成 VBLink.exe ,把我们写的 MyLink.exe 改成 Link.exe

到这一步,你应该懂了吧。。。

来做个示例

我新建了一个 ActiveX DLL 的工程,添加了一个 Module ,写了一个 Public Function ,如下

Public Function Add(ByVal A As Long) As Long

Add = A + A

End Function

生成“ E:\Math.dll

被截获的命令行( VB 默认命令行)如下:

"E:\Class1.OBJ" "E:\Module1.OBJ" "E:\Math.OBJ" "C:\Program Files\Microsoft Visual Studio\VB98\VBAEXE6.LIB" /ENTRY:__vbaS /OUT:"E:\Math.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /DLL /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078

修改后命令行(修改后的命令行)如下:

"E:\Class1.OBJ" "E:\Module1.OBJ" "E:\Math.OBJ" "C:\Program Files\Microsoft Visual Studio\VB98\VBAEXE6.LIB" /ENTRY:__vbaS /EXPORT:Add /OUT:"E:\Math.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /DLL /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078

大家对比两行命令可以发现在 /ENTRY:_vbaS 后面,我增加了 /EXPORT:Add ,这就是关键所在

现在,我又新建了一个 EXE 工程,加一个 VB API 声明,代码部分:

Private Declare Function Add Lib "E:\Math.dll" (ByVal A As Long) As Long 'API 声明

Private Sub Form_Load()

MsgBox Add(2)

End Sub

看到效果没,成功了吧

至于 String 型么,投递时 StrConv(String,vbUnicode ) 返回时 StrConv(String,vbFromUnicode )

学了这个,大家不知道有没有什么心得呢,当然这个要看个人悟性的问题。师父领进门,修行在个人嘛,何况还是被我这种半调子的菜鸟教呢

这个 ... 天好蓝 ... 水好清 ... 外挂 ...Winsock...API...DLL... 监视 API 的值 ... 修改 ... 嘿嘿 ... 我什么都没说

如果遇到不懂的地方 ... 就来问我啊 ...QQ 594363468