⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vb-dll.txt

📁 介绍VB写标准DLL的方法
💻 TXT
📖 第 1 页 / 共 2 页
字号:
win32 api就是windows dll
通常,一个静态库用在app的开发中,库没空必须链接到完成的app中。在动态链接中,模块是在另一个分离的dll中,是动态链接到app上。

动态链接库包括内部函数,只能从dll内部调用,如果是输出函数,可以从别的模块中(dll或者app)调用。 通常,.def文件在c/c++工程中来列出dll的输出。

一个dll也包含一个当被一个进程或者线程装载或者卸载的可选择入口点。当装载和卸载dll时windows调用这个入口点(entry point),同样当进程创建和结束时也调用这个入口点。这样可以使dll执行每个进程和每个app的初始化和清除工作。这个入口点在vb中的语法:
Public Function DllMain(hinstDLL As Long, fdwReason As Long, 
lpwReserved As Long) As Boolean

hInstDLL, long类型 包含了dll的 instance handle 句柄. 也是dll的模块句柄(DLL's module handle.)

fdwReason, 常数标识 入口点为何被调用,可能值为:

DLL_PROCESS_ATTACH (1)
进程装载了dll,每进程初始化要执行。A process is loading the DLL. Any per-process initialization should be performed. 
DLL_THREAD_ATTACH (2)
进程交换(注入)一个新的线程,每线程初始化要执行。The process is spawning a new thread. Any per-thread initialization should be performed. 
DLL_THREAD_DETACH (3)
一个线程结束。每线程清除要执行。A thread is exiting. Any per-thread cleanup should be performed. 
DLL_PROCESS_DETACH (0)
一个进程断开dll链接,或者进程结束,每进程清除要执行。A process is detaching the DLL, or the process is exiting. Any per-process cleanup should be performed. 

lpvReserved
一个long类型提供更多关于 DLL_PROCESS_ATTACH 和 DLL_PROCESS_DETACH的信息. (如果fdwReason是 DLL_THREAD_ATTACH or DLL_THREAD_DETACH,则该参数无用) 如果fdwReason 是 DLL_PROCESS_ATTACH, lpvReserved值无意义对于用函数 LoadLibrary and GetProcAddress装载dll, 如果 fdwReason 是 DLL_PROCESS_DETACH, lpvReserved值无意义,如果返回值是从 Win32 FreeLibrary function, lpvReserved值也无意义,如果进程结束调用入口点.

函数的返回值只有在fdwReason 是 DLL_PROCESS_ATTACH才有意义,如果初始化成功,函数返回true,否则返回false.因为这个函数是window调用的入口点.传入这个函数的参数值是由windows决定.当一个线程被用win32 TerminateThread 函数和 Win32 TerminateProcess 函数结束,没有调用入口点.


dll代码

要开发一个windows dll,我们创建一个简单的数学函数库,下面代码存在一个.bas模块中名字:MathLib.bas
Option Explicit

Public Const DLL_PROCESS_DETACH = 0
Public Const DLL_PROCESS_ATTACH = 1
Public Const DLL_THREAD_ATTACH = 2
Public Const DLL_THREAD_DETACH = 3

Public Function DllMain(hInst As Long, fdwReason As Long, 
lpvReserved As Long) As Boolean
Select Case fdwReason
Case DLL_PROCESS_DETACH
' No per-process cleanup needed
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH
' No per-thread initialization needed
Case DLL_THREAD_DETACH
' No per-thread cleanup needed
End Select
End Function

Public Function Increment(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5

Increment = var + 1
End Function

Public Function Decrement(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5

Decrement = var - 1
End Function

Public Function Square(var As Long) As Long
If Not IsNumeric(var) Then Err.Raise 5

Square = var ^ 2
End Function

开头包含一个DllMain过程,没有每进程或者每线程初始化需要执行。如果fdwReason参数是DLL_PROCESS_ATTACH被调用,DllMain简单的返回True。

另外,注意dll的函数中的输入参数和返回值用win32 api类型,不要用variant。

我们同样需要一个测试程序(test)验证我们的windows dll是否运行正常,所以创建个标准exe工程,由一个窗口和一个模块组成,模块代码就是declare声明。
Public Declare Function Increment Lib "MathLib.dll" (var As Integer) As Integer

Public Declare Function Decrement Lib "MathLib.dll" (var As Integer) As Integer

Public Declare Function Square Lib "MathLib.dll" (var As Long) As Long
如果不在系统路径,最好加上dll全路径。

窗口代码调用dll:
Option Explicit

Dim incr As Integer
Dim decr As Integer
Dim sqr As Long

Private Sub cmdDecrement_Click()
decr = Increment(decr)
cmdDecrement.Caption = "x = " & CStr(decr)
End Sub

Private Sub cmdIncrement_Click()
incr = Increment(incr)
cmdIncrement.Caption = "x = " & CStr(incr)
End Sub

Private Sub cmdSquare_Click()
sqr = Square(srr)
cmdSquare.Caption = "x = " & CStr(sqr)
End Sub

Private Sub Form_Load()
incr = 1
decr = 100
sqr = 2
End Sub

ActiveX DLL工程:

我们创建个ActiveX Dll,然后用调用win32 dll的方式来调用,看会出现什么问题。当创建ActiveX DLL工程,vb会自动添加一个类模块.cls文件到工程,可以改成你想要的名字,但是不要写任何代码,然后添加个模块.bas文件到工程中,并添加DLL代码,最后编译DLL,当运行测试工程(test)是,一个运行错误消息出现,找到指定的dll,但是调用dll函数出错,不能找到函数入口点。

通常这个错误就是因为函数没有被dll输出。我们可以使用DumpBin工具来检查一个dll的输出:
Dumpbin <path and name of dll> /exports
运行后可以看出:
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.


Dump of file mathlib.dll

File Type: DLL

Section contains the following exports for MathLib.dll

0 characteristics
41B9E52C time date stamp Fri Dec 10 10:04:28 2004
0.00 version
1 ordinal base
4 number of functions
4 number of names

ordinal hint RVA name

1 0 0000192E DllCanUnloadNow
2 1 00001902 DllGetClassObject
3 2 00001918 DllRegisterServer
4 3 000018EC DllUnregisterServer

Summary

1000 .data
1000 .reloc
1000 .rsrc
1000 .text

我们的dll有4个函数,都是支持com的函数,但是怎样输出DllMain和3个数学函数呢。vb不能显示的帮我们从ActiveX Dll输出 dll函数,因此限制了创建windows dll。

虽然困难,但是并不是不可能。当我们选择文件>编译<filename>.dll菜单选项来编译ActiveX dll,vb把我们的代码无缝结合成ActiveX dll,但是当我们检查vb的安装目录,其实这个过程并不是无缝的。在vb安装目录除vb6.exe,还有C2.exe和link.exe,一个是编译器,一个是链接器,这里就说明vb6.exe本身不能生成dll文件,而dll是由这2个程序一起运行生成的。

我们可以通过改名C2.exe和link.exe来中断编译器和链接器的执行过程来发现vb是如何编译的。下面的代码是个新版本的C2.exe调用真正的C2.exe编译器,我们把原始C2.exe命名为C2comp.exe:
Public Sub Main()

On Error Resume Next

Dim strCmd As String, strPath As String
Dim oFS As New Scripting.FileSystemObject
Dim ts As TextStream

strCmd = Command

strPath = App.Path

Set ts = oFS.CreateTextFile(strPath & "\c2log.txt")

ts.WriteLine "Beginning execution at " & Date & " " & Time()
ts.WriteBlankLines 1
ts.WriteLine "Command line parameters to c2 call:"
ts.WriteLine " " & strCmd
ts.WriteBlankLines 1
ts.WriteLine "Calling C2 compiler"

Shell "c2comp.exe " & strCmd
If Err.Number <> 0 Then
ts.WriteLine "Error in calling C2 compiler..."
End If

ts.WriteBlankLines 1
ts.WriteLine "Returned from c2 compiler call"
ts.Close

End Sub

注意只是个标准的exe,没有form,subMain启动,引用fso。然后我们重新编译刚才的ActiveX dll出现下面的信息:

Beginning execution at 12/10/2004 12:44:22 PM

Command line parameters to c2 call:
-il "C:\DOCUME~1\Ron\LOCALS~1\Temp\VB277103" -f "C:\VB Projects\
MathLib\MathMod.bas" -W 3 -Gy -G5 -Gs4096 -dos -Zl -Fo"C:\
VB Projects\MathLib\MathMod.OBJ" -QIfdiv -ML -basic

Calling C2 compiler

Returned from c2 compiler call

从命令行中我们可以看出生成给链接器执行的object文件,就是说怎么创建windows dll,我们必须中断调用链接器,这样我们可以看到vb传递了什么参数。看下面代码:
Public Sub Main()

On Error Resume Next

Dim strCmd As String, strPath As String
Dim oFS As New Scripting.FileSystemObject
Dim ts As TextStream

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -