1、VB 封装 DLL 实例讲解(一)一、 DLL 基本概念(一)概念DLL 即动态链接库(Dynamic Link Library) ,是由可被其它程序调用的函数集合组成的可执行文件模块。DLL 不是应用程序的组成部分,而是运行时链接到应用程序中。(二)主要优点:1、多个应用程序可以共享一个 DLL,而且当多个应用程序调用库的同一个函数时,可执行文件中装入的只是该函数的内存地址,从而节省内存和磁盘空间;2、使用动态链接库易于我们维护用户程序,即使对动态链接库进行修改也不会影响用户程序;3、从 ACCESS 角度而言,还可以更好的确保核心代码的安全。二、 用 VB 封装 VBA 代码,构建自定义的
2、 DLL 动态链接库(一)ACCESS 中实例代码下面是一个“快速提取字符串中数字.mdb ”实例(该实例在文件包中) ,单击“提取结果”按钮,将文本框中的数字在弹出消息显示出来。我将就这个实例演示如何将该实例 VBA 代码封装成为 DLL。 按钮单击事件代码如下:Private Sub CmdFindnumber_Click()Dim strM As String 初始字符串Dim strOut As String 输出字符串变量Dim IstrM = Me.Text1从第一个字符向最后一个字符循环,以提取每个字符For I = 1 To Len(strM)判断是否为 0 到 9 字符,是则
3、赋值输出If Mid(strM, I, 1) Like “0-9“ ThenstrOut = strOut & Mid(strM, I, 1)End IfNext I用 MsgBox 函数进行输出测试MsgBox strOutEnd Sub 以上代码还不能直接用于封装, 须将其修改成为公用函数( 过程)(二)VB 封装实例中 VBA 代码步骤一:在 VB 编辑窗中,点菜单【文件】-【新建工程】 ,打开新建工程窗口步骤二:修改工程名,这即生成的 DLL 库名1、点选 ActiveX DLL2、点确定1、修改工程名为:我的动态库步骤三:修改类名步骤四:在代码窗口输入如下代码。将 ACCESS 中的
4、单击事件代码,略做修改成为一个公用函数,然后复制到 VB 代码编辑窗口1、改类名为:提取数字代码如下将这前的 ACCESS 代码改成一个公用函数输入:strPutString 字符串变量,需分离数字的字符串输出: fFindNumber 字符串变量,得到的数字字符Public Function fFindNumber(strPutString As String) As StringDim strOut As String 输出字符串变量Dim I从第一个字符向最后一个字符循环,以提取每个字符For I = 1 To Len(strPutString)判断是否为 0 到 9 字符,是则赋值输出
5、If Mid(strPutString, I, 1) Like “0-9“ ThenstrOut = strOut & Mid(strPutString, I, 1)End IfNext I数字输出fFindNumber = strOutEnd Function步骤五:编译 DLL,点菜单【文件】-【生成我的动态库.dll】 ,VBA 代码封装 DLL 就完成了。三、 在 mdb 中调用自定义 DLL 动态链接库(一)新建数据库及窗体新【快速提取数字(DLL)实例.mdb】数据库,新建一个窗体【frmMain】,在窗体添文本框【text0】,按钮【CmdFindNum】,Caption 属性:
6、“提取数字”(见下图)(二)引用【我的动态库.dll】库按【Alt+F11】打开 VBE 窗口,点菜单 【工具】-【引用】 ,打开引用对话框,完成对我们自己编译的 DLL 的引用。(三)在【CmdFindNum】按钮单击事件中加入如下代码。Private Sub CmdFindNum_Click()申明自定义类Dim MyFindNum As 提取数字Dim strOut As String实例化“ 提取数字类“ 对象Set MyFindNum = New 提取数字将函数输出结果赋值给自定义字符串变量strOut = MyFindNum.fFindNumber(Text0)在消息框中显示Msg
7、Box “你提取的数字为:“ & strOut, vbInformation, “江羽提示:“End Sub点击保存后,你就可以运行一下窗体测试你的成果了 本文实例见实例包,下 载测试如果提示错误,请重新对自定义类库进行引用。本文只是通过一个简单的实例演示了,如何通过 VB 封装一般的 VBA 中代码,因为该代码中并未涉及到 ACCESS 应用程序对象,所以在 VB 中没有对 ACCESS 对象类库进行引用,另外实例中只是简单演示了,如何手动实现对 DLL 的注册引用,在后续文章中我将就如何实现 DLL 与 ACCESS 应用程序对接及 DLL 的自动注册及引用结合实例进行讲解。江羽 2010
8、-05-16 晚2、选择引用的 DLL3、点打开1、点浏览4、点确定VB 封装 DLL 实例讲解(二)上文中我们已经就 DLL 的基本概念,以及如何将 VBA 代码封装为 DLL,如何引用该生成的 DLL动态链接库,进行了初步的讲解,我想大家对于 VB 封装 DLL 应该有了一个初步的了解。下面主要就 DLL 如何实现对 ACCESS 对象进行封装方法进行探讨。一、如何在 VB 中实现对 ACCESS 对象编程(一)在 VB 中引用 ACCESS 对象类库我们要通过编译 DLL 来实现对 ACCESS 对象的封装,首先必须在 VB 中引用 ACCESS 对象类库,这样我们就可以在 VB 中,实
9、现对 ACCESS 应用程序中的对象进行编程。打开 VB 编辑窗口,点菜单【工程】-【引用】 ,打开【引用对话框】 ,点选“Microsoft Access 11.0 Object Library”完成对当前版本 ACCESS 应用程序对象的引用。(实例演示版本为 ACCESS 2003) 对 ACCESS 对象库的引用很关键,否则我们无法实现对 ACCESS 对象的编程(二)了解 ACCESS 对象模型在 VB 中要对 ACCESS 对象进行编程,还必需对 ACCESS 所提供的各项对象有一定了解,因为 VB就是通过 ACCESS 对象的方法与属性,来完成各项操作与设置,下图为 ACCESS
10、 2003 的对象部分模型图例。库文件所在路径1 钩选 ACCESS 对象库2 点击确定 上图为 ACCESS 2003 对象模型,因为篇幅的问题,文中只显示模型中部分对象,要了解全部 对象模型,请大家参阅帮助。(三)VB 编程中 ACCESS VBA 与 VB 对象表述区别1、ACCESS VBA 与 VB 的顶层对象都为 Application ,但在编程中 ACCESS VBA 顶层对象表述为:Application ,而在 VB 编程中顶层对象用简写: App 表述(到 VB.NET 又改回了 Application) 。 例程:在 VB 编程中获得 VB 及 ACCESS VBA 获
11、取当前路径实例:在 VB 中获得当前路径:App.Path在 VB 中获得 ACCESS 的当前路径:Application.CurrentProject.Path 在 office 各应用程序之间调用各组件时,通常在对象前加上库名,如:Access.Application 来表述,但因为 VB 与 ACCESS 顶层对象原本表述就存在区别,在 VB 中可以直接用 Application 表述 ACCESS 应用程序对象,并不会产生冲突的 问题。2、ACCESS VBA 和 VB 中部分预定义类对象(如:窗体、控件等)表述基本相同,以“标签控件”为例,VB 与 ACCESS VBA 均为 La
12、bel,在 VB 编程中为了与 ACCESS 预定义类对象加以区别,ACCESS 标签对象通常用 ACCESS.Label 表述。 例程:在 VB 编程中定义 VB 及 ACCESS 标签控件对象实例:在 VB 中定义 VB 标签对象:Dim m_Label As Label在 VB 中定义 ACCESS 标签对象:Dim m_Label As Access.Label 在进行 DLL 编程时,特别需注意对象表述区别的问题 ,否则无法编译或是编译后在 ACCESS调用中报错。(四)VB 编程中关于 ACCESS VBA 专属常量ACCESS VBA 专属常量以“ac”开头,如:控件类( AcC
13、ontrolType)中的文本控件常量为acTextBox,这些常量不一定能被 VB 所识别,解决办法通常不使用“常量名” ,而直接使用“常量值” ,或以输入参数方式传递的方法来解决。 例程:实现隐藏所有文本控件。acTextBox 常量值为 109。Dim ctl As Access.Control 申明 ACCESS 控件对象Dim frmClt As Access.Controls 申明 ACCESS 控件集合遍历所有 ACCESS 控件集合,如为文本控件,则不显示该控件For Each ctl In frmClt.Controls文本控件类常量值为 109,以常量值替代 acTextB
14、ox 常量名If ctl.ControlType = 109 Then ctl.Visible = FalseNext 你可以通过帮助查阅 ACCESS 专属常量值,也可以在 ACCESS VBA 中通过程序方式获取,如:在立即窗口输入:?acTextBox 回车,就可以 acTextBox 常量值为:109。二、DLL 封装 ACCESS 对象实例演示(一)ACCESS 的 MDB 实例MDB 实例演示获得 ACCESS 版本信息,并在标签 Label0 中显示(见下图) ,具体参看实例中frmVer6 窗体中的代码,及类模块 ClsVeresion 中代码。 mdb 实例中 frmVer1
15、-frmVer6 各窗体中具体演示了,代码按 DLL 封装需要整理的思路。 例程:frmVer6 窗体加载事件代码 Private Sub Form_Load()申明自定义类的实例Dim m_Ver As New ClsVeresion m_Ver.objAddItem Label0 调用自定义类的 objAddItem 方法End Sub 例程:ClsVeresion 类模块代码 程序功能:定义类接口,将版本信息输出并在标签中显示Public Sub objAddItem(m_label As Label)m_label.Caption = AppVersionEnd Sub函数功能:输出
16、ACCESS 版本信息Private Function AppVersion() As StringDim strVer As String 定义字符串变量将版本号赋值给字符串变量strVer = Application.Version根据版号输出对应版本信息Select Case strVerCase “8.0“AppVersion = “Access 97“Case “9.0“AppVersion = “Access 2000“Case “10.0“AppVersion = “Access 2002“Case “11.0“AppVersion = “Access 2003“Case “12
17、.0“AppVersion = “Access 2007“End SelectEnd Function(二)DLL 的封装 ACCESS 对象实现1、打开 VB6.0 编辑器,点菜单【新建工程】 ,在【新建工程】对话框中,点选【ActiveX DLL】 ,点【确定】 。2、修改工程名及类名,实例中我定义的工程名:GetAccVer ,类名:ClsAccVer ,修改完成以后点选菜单【保存】工程 (见下图)。 工程名就是我们后面将引用的 DLL 库名,类模块名为代码中我们申明的类名。3、点菜单【工程】-【引用】 ,打开【引用对话框】 ,点选“Microsoft Access 11.0 Objec
18、t Library”完成对当前版本 ACCESS 应用程序对象的引用。4、将 MDB 中类模块 ClsVeresion 代码复制到 VB 中 ClsAccVer 类模块中,按前面我们所述的 VB中实现 ACCESS 对象编程的注意要点略做修改。 (见下图划红线部分) 1、因 为 VB 与 ACCESS VBA 中标签类对象都为 Label,因此加上库名(Access.Label)加以区别;2、因为 VB 与 ACCESS VBA 顶层应用程序对象,表述原本就有区别,所以无需特别区分。 例程:ClsAccVer 类模块代码 程序功能:定义 DLL 接口,将版本信息输出并在标签实例中显示Publi
19、c Sub objAddItem(m_label As Access.Label)m_label.Caption = AppVersionEnd Sub函数功能:输出 ACCESS 版本信息Private Function AppVersion() As StringDim strVer As String 定义字符串变量将版本号赋值给字符串变量strVer = Application.Version根据版号输出对应版本信息Select Case strVerCase “8.0“AppVersion = “Access 97“Case “9.0“AppVersion = “Access 200
20、0“Case “10.0“AppVersion = “Access 2002“Case “11.0“AppVersion = “Access 2003“Case “12.0“AppVersion = “Access 2007“End SelectEnd Function4、编译 DLL,点菜单【文件】- 【GetAccVer.dll】动态链接库,封装 DLL 就完成了。你现在可以在 ACCESS 中引用该 DLL 测试一下看看成果了。参看实例中 frmVer7 窗体,如实例引用报错,请重新引用 GetAccVer.dll 即可。因为本人认知及文字水平所限,不免有错漏之处,还请大家斧正。本文的
21、Word 文稿、VB 源码、MDB 实例均在实例包中。在后文中我们主要就动态链接库引用的方法和技巧结合实例进行探讨。江羽 2010-05-30 午VB 封装 DLL 实例讲解(三)一、手动注册及引用(一)手动注册及引用方法(参看实例:手动引用.mdb)进入 VBA 编辑窗口,点菜单【工具】【引用】 ,打开【引用】对话框,点【浏览】按钮,打开【添加引用】对话框,点选要引用的 DLL(测试实例为:ClsFindString.dll) ,点【打开】点【确定】 ,我们完成动态链接库的手动注册及引用。(二)手动注册及引用方法不足及问题手动注册引用优点是不言而喻的,方便简捷,易于操作。但在实际运用中,当我
22、们在其他电脑上发布应用程序,或运行我们测试好的应用程序时,却会出现错误提示,程序无法正常运行。错误(一):找不到工程或库(见下图)错误的主要原因:DLL 在当前运行的电脑系统中没有注册信息,而且引用不正确。错误(二):引用的动态链接库(DLL)丢失(见下图)进入到 VBA 编辑窗口,点菜单【工具】【引用】 ,打开【引用】对话框,我们会看到之前引用的1 点浏览按钮2 点选 DLL3 点打开按钮4 点确定按钮DLL 动态链接库丢失。错误的主要原因:系统无法找到原路径引用 DLL。错误(三):自动化错误(见下图)错误的主要原因:我们在发布应用程序的电脑或系统中,虽然重新完成 DLL 手动注册和引用,
23、但如果 DLL 路径再次改变,运行程序时就会出现“自动化错误”提示。错误(四):ActiveX 部件不能创建对象(见下图)错误的主要原因:应用程序已正常引用 DLL 动态链接库,但其册注信息丢失或者没有正常注册,就会出现以下问题。(三)解决上述错误方法1、解决错误方法,当然是重新进行 DLL 的手动注册及引用,具体步骤参下图。但这只是治标不治本的办法,不利于对外发布我们的应用程序,最好的办法还是通过 VBA 自动完成 DLL 的注册及引用。二、自动注册及引用 DLL方法在探讨如何实现 DLL 自动注册及引用之前,我们必须清楚一点,那就是 DLL 的注册与引用并不是同一事件或行为的两种不同表述,
24、而是两种不同的动作。2 点浏览按钮3 点选 DLL4 点打开按钮5 点确定按钮1 去除丢失 DLL 钩选 DLL 注册是指将 DLL 的相关信息,如:DLL 唯一识标号(GUID ) ,版本号(Version )及路径(Path)信息写入注册表中,以供系统对 DLL 进行识别调用。我们通过 VB 编译生成 DLL 时,VB 一般会自动完成对该 DLL 的注册,但如果要在其它电脑上运行程序时,我们就必须重新对该 DLL 进行注册。 DLL 引用是指将 DLL 类库对象集成到代码编辑环境中,以便编程时调用类库中的对象、属性及方法。我们通过手动方式完成 DLL 的引用时,系统会自动完成对该 DLL
25、的注册,所以我们无需另行对DLL 进行注册,但如果我们在其它电脑上运行程序时,还会出现我们在之前章节中所述的错误。(一)DLL 自动注册方法我们可以通过 Regsvr32.exe 来进行 DLL 注册或反注册,具体的语法及参数:语法: Regsvr32 /u /n /i:cmdline dllname说明:其 中 dllname 为 DLL 文 件 名 ,建 议 在 发 布 时 将 DLL 复 制 到 system 文 件 夹 下 。参数:参数 说明/u 反 注 册/s 指 定 regsvr32 安 静 运 行 , 且 不 显 示 任 何 消 息 框 。/n 指 定 不 调 用 DllRegi
26、sterServer。 此 选 项 必 须 与 /i 共 同 使 用 。/i:cmdline 调 用 DllInstall 将 它 传 递 到 可 选 的 cmdline。 在 与 /u 共 同 使 用 时 , 它 调 用 dll 卸载 。dllname 指 定 要 注 册 的 dll 文 件 名 。1.1 示 例 通 过 Shell 运 行 Regsvr32 程 序 完 成 DLL 注 册 Shell “Regsvr32 /S “ & Chr(34) & CurrentProject.Path & “ClsFindString.dll“ & Chr(34)Shell 函数 用以运行 Regs
27、ver32 程序Regsver32 注册程序/S 注册程序参数,书写时记得参数前后必须留空Chr(34) Chr 函数,获指定代码字符,Chr(34)为引号CurrentProject.Path DLL 当前路径ClsFindString.dll 演示实例 DLL 名1.2 示 例 通 过 Shell 运 行 Regsvr32 程 序 反 注 册 Shell “Regsvr32 /U /S “ & Chr(34) & CurrentProject.Path & “ClsFindString.dll“ & Chr(34)我们可以将注册语句放在窗体的加载事件,自动完成 DLL 的注册,具体可以参看
28、实例。但如果我们有多个 DLL 需要批量注册时,可以考虑通过软件打包发布工具来完成 DLL 的注册工作;也可以事先编写 BAT 文件,让打包发布时将该 BAT 文件一并打包发布,安装时运行该 BAT 文件,来完成 N 个DLL 的批量注册,在些就不多着笔墨,大家可以参看实例包中的 BAT 文件实例。(二)DLL 自动引用方法2.1 通 过 References 对 象 的 AddFromFile 方 法 实 现 自 动 引 用Dim ref As Reference 申明引用类对象On Error Resume Next 避免因重复引用造成的错误提示实例化引用对象,完成 DLL 的引用Set
29、ref = References.AddFromFile(CurrentProject.Path & “ClsFindString.dll“)为了避免因重复引用出现的错误,我们可以如上代码中加入 Error 语句,我们还可以在应用程序退出时,通过对 References 对象的 Remove 方法释放 DLL 或反引用。Dim ref As Reference 申明引用类对象实例化反引用对象Set ref = References(“ClsFindString“)移除引用指定类库References.Remove ref说明:根据本人实践,我个人倾 向于使用 Error 语句,因为如果应用程序
30、非正常退出,引用对象没有反引用成功,启动时就难免出现 重复引用的错误问题。2.2 通 过 DLL 唯 一 标 识 号 实 现 自 动 引 用Dim ref As Reference 申明引用类对象On Error Resume Next 避免因重复引用造成的错误提示唯一标识号完成注册,需要 DLL 标识号,主版本号,次版本Set ref = References.AddFromGuid(“C5E340E2-C557-4852-AE83-5A0578B6863B“, 1, 0)DLL 的标识号是编译生成时就确定了的,这个标识号就是 DLL 的终生制身份证号,我们可以通过这个唯一标识号来完成 DL
31、L 自动引用。但此种方法必须具备两个条件,一是 DLL 已经成功注册,二是我们知道了该 DLL 的标识号、主版本号、次版本号。2.2.1 获 取 DLL 标 识 号 、 主 版 本 号 、 次 版 本 号 方 法Dim ref As Reference 申明引用类对象实例化引用类库对象Set ref = References.AddFromFile(CurrentProject.Path & “ClsFindString.dll“)Debug.Print ref.GUID 获得 DLL 唯一标识号Debug.Print ref.Major 获得主版本号Debug.Print ref.Minor
32、 获得次版本号2.3 通 过 CreateObject 方 法 实 现 自 动 引 用Dim DllFindStr As Object 申明对象实例化对象为创建的 DLL 类库对象ClsFindstring 为 DLL 库名,clsFindStr 为 DLL 类名Set DllFindStr = CreateObject(“ClsFindstring.clsFindStr“)DllFindStr.sFindStr Text2, Me.Text0 调用 DLL 类库方法,运行程序Set DllFindStr = Nothing 释放对象根据我本人实践经验,CreateObject 方法自动引用是最为便捷高效的方法,仅供参考。关于 DLL 相关自动注册及引用方法就探讨这里,以上文字仅是本人实践的一点总结,希望对大家有所帮助,如有错漏之处还请大家斧正。本文的 Word 文稿、 DLL 源码(含 DLL) 、mdb 演示实例及BAT 注册文件实例均在实例包中。江羽 2010-06-01 晚