ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 62538|回复: 110

[原创] 我的vba封装学习过程

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-10-23 16:14 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:封装
本帖最后由 zhanglei1371 于 2014-10-23 16:44 编辑

很早就想学习下如何将vba代码封装为dll的技术,终于有了空闲的时间,将这个过程研究了下,花了3天时间,总算能做出个小工具了。其实论坛和百度有不少教程,但即便是有教程和很多参考,但是仍旧有很多问题:
1. 论坛九成的教程都是基于excel的,专门针对word的很少;
2. 即使参照word的能找找到的东西去做,但是都是比较浅显,多数止步于msgbox测试对话框;
3.没有系统的从代码 →安装程序的过程。
故此,我打算将原始代码,稍微复杂些的情况也加进去,将代码如何封装,常用封装方法,优点缺点,直至封包为安装程序的完整过程写出来,算是对自己学习的一个总结吧。

在此特别感谢loquat提供的资料和帮助,没有他的帮助不会有本文的产生。

由于本人水平有限,中间还有我自己不明白的不少问题没有解决,甚至还有些纰漏之处,大家可跟帖补充。

过程框架:
1.  三种封装为dll的方法:ActiveX类模块、AddinInstance接口和IDTExtensibility2接口,后面两个也就是COM加载项。
2. dll通过批处理注册的方法;
3. 制作成安装程序的方法:winrar、wise install system和setupfactory。









评分

10

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:15 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-23 17:04 编辑

需要的软件:VB6.0
office版本:2003
封装方法一、制作成为ActiveX dll其实对于这个个人感觉不如COM加载项有优势,因为对象支持的不如com加载项多。不过既然是dll,肯定能起到保护代码,无法被查看,即使使用vb_decompiler,得到的也是一堆垃圾,根本看不出有价值的东西。可以同时做出通用于word、excel、ppt的dll。
如下图:
图片1.png
封装为dll后即使用反编译软件vbdecompile查看,能看到标题,但内容却是和乱码无异。没有任何价值。
和com相比缺点:无法产生菜单、按钮。【也许可以,不过没找到教程介绍增加按钮的。】
实质:其实就是将过程搞进类模块中,然后通过类模块来执行相应的子过程。
步骤:
1. VB中创建工程:选择ACtiveXdll,右侧修改类模块名字为自己想要的名字,我的为MC。
001.jpg 002.jpg
2. 左侧窗口输入代码:
从我一年前发的得意之作中选几个作为测试代码:
http://club.excelhome.net/thread-1048572-1-1.html

  1. Public wd As Word.Application
  2. 'word中range、bookmarks、document、filedialog非vb对象,故需修改为object对象,所有对应的常量都应设置为值!
  3. Sub excel测试()
  4. Dim ex As Excel.Application
  5. Set ex = GetObject(, "excel.application")
  6. ex.ActiveSheet.Range("D3") = 456789
  7. ex.ActiveSheet.Range("F6").Value = "这是一个测试!!!"
  8. End Sub
  9. Sub word写入测试()
  10. 'On Error Resume Next
  11. Dim wd As Word.Application
  12. Set wd = GetObject(, "word.application")
  13. wd.Selection.TypeText "12345678" & vbNewLine
  14. wd.ActiveDocument.Range.InsertAfter "sdafasdfsadf45856"
  15. MsgBox "sdafsdaf"
  16. End Sub
  17. Sub ppt写入测试()
  18. Dim pt As PowerPoint.Application
  19. Set pt = GetObject(, "powerpoint.application")
  20. pt.ActivePresentation.Slides(1).Shapes(1).TextFrame.TextRange = "这是本类模块在ppt中的一个测试!" '写入第一个ppt中第一页的第一个文本框
  21. pt.ActiveWindow.Selection.TextRange.Text = "这个是对ppt中选定文本框写入的一个测试!!!" '写入选定文本框
  22. End Sub
  23. Sub 删除全文空白行()
  24. Dim t#
  25. Set wd = GetObject(, "word.application")
  26.     wd.ScreenUpdating = 0
  27.     t = Timer
  28.     Dim S As Object
  29.     Set S = wd.ActiveDocument.Content   '
  30.     S.Find.Execute "^13[  ^t" & ChrW(160) & "^11^13]{1,}", , , 2, , , , , , "^p", 2
  31.     Set S = Nothing
  32.     wd.ScreenUpdating = 1
  33. End Sub
  34. Sub 计算()
  35. Set wd = GetObject(, "word.application")
  36. a = 4
  37. B = 5
  38. MsgBox a + B
  39. wd.ActiveDocument.Content.InsertAfter a & B
  40. End Sub
  41. Sub 自动编号替换为手动编号()
  42. Dim S As Object
  43. Set wd = GetObject(, "word.application")
  44. If wd.Selection.Type = wdSelectionIP Then wd.Selection.Expand wdParagraph
  45. Set S = wd.Selection.Range
  46. wd.Selection.Range.ListFormat.ConvertNumbersToText
  47.     With wd.Selection.Find
  48.         .ClearFormatting
  49.         .Replacement.ClearFormatting
  50.         .Text = "([0-9]{1,})([..、^9^32" & ChrW(160) & ChrW(12288) & "]{1,})"
  51.         .Wrap = 0
  52.         .Replacement.Text = "\1. "    '此处可改为顿号或其他
  53.         .MatchWildcards = 1
  54.         .Execute Replace:=wdReplaceAll
  55.     End With
  56. End Sub
  57. Sub 每行插入表格n个图()
  58.     On Error Resume Next
  59.     Set wd = GetObject(, "word.application")
  60.     wd.ScreenUpdating = False
  61. Dim D As Object, a, P As InlineShape, t As Table
  62. Dim B$, C$ '这里就体现了不定义变量的缺点:不定义的话生成的图片下面没有名字。
  63. If wd.Selection.Information(wdWithInTable) = True Then MsgBox "请将光标置于表格之外!": Exit Sub
  64.     With wd.FileDialog(1) '★★★若是此处写成msoFileDialogFilePicker则不起作用,因为filedialog不是vb的对象,是vba特有,故其所有常量都应写值!!!★★★
  65.         .Title = "请选择..."
  66.         If .Show = -1 Then
  67.         n = InputBox("请输入表格的列数:", "列数", 3)
  68.         m = .SelectedItems.Count
  69.         Debug.Print "共有" & m & "个图片"; m
  70.    h = IIf(m / n = Int(m / n), 2 * m / n, 2 * (Int(m / n) + 1))
  71.    Set t = wd.ActiveDocument.Tables.Add(wd.Selection.Range, h, n)
  72.         t.Borders.Enable = True
  73. t.Borders.OutsideLineStyle = wdLineStyleDouble
  74.             For Each a In .SelectedItems
  75.                 B = Split(a, "")(UBound(Split(a, "")))
  76.                 C = Split(B, ".")(0)
  77.                 Set P = wd.Selection.InlineShapes.AddPicture(FileName:=a, SaveWithDocument:=True)
  78.                 With P
  79.                     w = .Width
  80.                     .Width = Int(410 / n)
  81.                     .Height = .Width * .Height / w
  82.                 End With
  83.                 i = i + 1
  84.                 wd.Selection.MoveLeft wdCharacter, 1
  85.                 wd.Selection.MoveDown wdLine, 1
  86.                 wd.Selection.TypeText C
  87. wd.Selection.Cells(1).Select
  88. wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter '决定了首行居中
  89. wd.Selection.HomeKey
  90. wd.Selection.MoveDown wdLine, -1
  91.                 wd.Selection.MoveRight wdCharacter, 2
  92.                 Debug.Print i, n
  93.                 If i = Val(n) Then
  94.                     wd.Selection.MoveRight wdCharacter, 1
  95.                     wd.Selection.Cells(1).Select
  96.                     wd.Selection.EndKey
  97.                     wd.Selection.MoveDown wdLine, 1
  98.                     i = 0
  99.                 End If
  100.             Next
  101.         End If
  102.     End With
  103.     wd.ScreenUpdating = True
  104. End Sub
复制代码
这里有几个注意事项,也就是涉及到代码需要修改的地方:
1. wd程序方面:必须有这句:Set wd = GetObject(, "word.application"),否则所以的word操作都是空的!
2. 有些对象需要设置为object:如bookmarks、document、filedialog、range,暂时我就发现这几个;其常量需要修改为值。上面的filedialog(1)中的1就是例子
3. 这种方式不仅可以用于word,还能用于ppt、excel,需要点击工程 →引用 →勾选相关项目:
004.jpg
确定即可。
没有问题后就点文件 →生成工程1.dll即可。

其实这里是比较简单的,有什么问题,点生成dll时会有相关提示,按照提示去修改即可。
不过难点就是无法像vba那样方便的调试。出一点问题就需要测试半天,麻烦的要死...
OK,下一步就是调用dll了。



TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:17 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-23 22:21 编辑

dll如何使用后面的com加载项中会有详细的制作安装程序的步骤,这里先说一般方法:
1.注册:其实就是win+R打开运行框,输入regsvr32 dll文件路径即可。如我的:regsvr32   D:\桌面\word加载项研究\3\4\工程1.dll,回车后会看到注册成功的标志。
如果卸载,很简单,将工程1.dll删除或者执行regsvr32 /u   D:\桌面\word加载项研究\3\4\工程1.dll即可。/u代表卸载unistall
2. 前面步骤完成后就是word中引用了,alt+f11打开vbe界面,如下图
111.jpg
勾选引用后就可以使用dll了:
测试下:MC为dll中的类模块的名字,mc中有的子过程都可以调用执行了。
Sub sd()  
Dim a As New MC
a.删除全文空白行
a.每行插入表格n个图
End Sub

这样就能执行dll中的相应过程了。
同样,在excel和ppt中也能引用测试:
excel中:
Sub te()
Dim a As New MC
a.excel测试
End Sub

004.jpg
ppt中也是一样:
Sub te()
Dim a As New MC
a.ppt写入测试
End Sub

001.jpg 002.jpg 003.jpg
大致步骤:vb选Activex dll →类模块中粘贴代码 →引用word,excel,ppt或其他组件 →生成dll →启动word,打开vbe输入sub,dim a as new 类模块等等,【NEw必须不可少★★★】 →测试效果 →出问题后花时间查找原因 →直至成功。
可以看出,总体还是比较简单的。不过最浪费时间的就是调试,一旦出了很小的问题,往往需要花费一个小时或更多时间去寻找原因。因为很多在 vba中能用的代码在ActiveX的dll中是不行的,甚至制作com后修改好的代码也是无法直接在里面使用,还需要二次修改。
总之,制作ActiveX dll对我而言只是尝试过程,相比COM就显得比较鸡肋了。个人更喜欢做成COM的形式。
下面是COM的制作过程。。。




ActiveX -dll.rar

14.15 KB, 下载次数: 372

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:17 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-23 22:51 编辑

                                  COM封装个人认为这是最理想的封装方式,因为这样处理后,生成的dll完全可以是图文并茂,菜单按钮俱全,直接就可以点击执行我们需要的功能了。而不是像上面的dll一样,还需要去手动勾选引用,再用代码去调用dll中的模块,显得非常繁琐。不过也有个好处,就是保护源代码,仅此而已,另外对快捷键也不影响,可以设置自定义快捷键没有问题。好像就这么多优点了。而com加载项则是除了快捷键比较麻烦外,其他的和normal几乎是一样了。【快捷键就是为宏自定义的快捷键,如按Alt+s实现自动段落缩进,Ctrl+SHift+r实现自动删除选中区域的空格、空行等,一旦做成了com,都会失效,必须重新使用新的手段,新的代码才能重新设定,我暂时还不会这个】
但是,对应vba白痴而言,或者电脑盲而言,最好的发布方法就是给他个安装程序,直接点击下一步,下一步...直至完成,这是最好的方法。因此,COM是我最喜欢的方式了。
                       使用AddinInstance接口


1.开始操作和上面的基本一样,只是开始时选择的不是ActiveXdll,而是外接程序【英文版vb6会显示为addin】
001.jpg
2.在右侧删除窗体部分模块,保留connect部分,双击,按左图设置,startup表示word一启动就自动运行,当然不希望如此还可选择load on demand
除了Connect模块外,其他的窗体,类模块统统删除,因为要写我们自己的,这些用不着的东西全部干掉。右键connect,查看代码,将默认的删除掉。
工程名称可修改名称为自己的,我的是修改为了测试com

002.png 003.png
3.右键查看代码,删除全部默认的代码,点通用【这是默认可看到就是AddinInstance】,确定,然后右侧窗口下拉菜单选择disconnect,出现下图:

004.png
默认会出现一堆代码【Private Sub AddinInstance_OnConnection(ByVal Application As Object, ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)和Private Sub IDTExtensibility2_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, custom() As Variant)】,不用管,原来一直以为这些代码是需要自己去思考写出的,故望而却步,其实是系统生成的【若不是系统自动生成,我再学2年vba也写不出来,其实目前我也看不懂什么意思 0001.jpg 】,不需理会。写入两个测试msgbox即可:


005.png
虽说只有短短两句,但是却生成了一堆东西:编译为dll后又生成了一个dll,对于发布而言,有dll就足够了。其他的东西是修改源码用的,不用管。

006.png 007.png
4.点击文件 →生成XXX.dll,然后regsvr32 进行注册,和前面所说相同,注册后就能打开word和关闭word看到效果了。
由于这个太简单了,就不再提供附件了。
接下来是更实用的东西,添加工具栏,按钮,窗体。。。。

0001.jpg

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:18 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 zhanglei1371 于 2014-10-24 13:59 编辑

更复杂的操作:添加按钮
接着刚才的操作,工程——引用word
001.png
修改connect
Private Sub AddinInstance_OnConnection(ByVal Application As Object, ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)
Set wd = Application
Call 增加我的按钮  ‘call可省略掉
End Sub

Private Sub AddinInstance_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, custom() As Variant)
Set wd = Nothing
End Sub

002.png .
*******************类模块的作用***********************
类可以提供事件的动作。
简单的例子:我们可以在vbe界面加入菜单,但是onaction却不起作用,怎么办?使用类。
想创建自己的方法属性,使用类可以做到。
所以,类和api都算是vba的中高级境界了。

**********************************************************
比如想要增加一个自己的工具栏,并在上面添加按钮,下列菜单,怎么做?
我的步骤:
首先在word中写好代码,然后粘贴到vb中去。

  1. Dim b As New 按钮
  2. Sub 增加我的按钮()
  3. CommandBars("menu bar").Reset
  4. '    CommandBars("新工具条").Delete
  5. Set x = CommandBars.Add("新工具条", msoBarTop)
  6.     With x
  7.         .Visible = True
  8.     End With
  9.         Set n = x.Controls.Add(Type:=msoControlButton)
  10.         With n
  11.             .Caption = "测试01"
  12.             .Tag = "测试00001"
  13.             .Style = msoButtonIconAndCaption
  14.             .FaceId = 456
  15.         End With
  16. Set b.btn = n
  17. Set m = CommandBars("menu bar").Controls.Add(1)
  18.     m.Caption = "测试02"
  19.     m.Tag = "测试02"
  20.     m.Style = msoButtonIconAndCaption
  21.     m.FaceId = 457
  22. Set b.btn = m

  23. Set m = CommandBars("menu bar").Controls.Add(1)
  24.     m.Caption = "测试03"
  25.     m.Tag = "测试03"
  26.     m.Style = msoButtonIconAndCaption
  27.     m.FaceId = 453
  28. Set b.btn = m

  29. End Sub
复制代码
=========================================
  1. Dim b As 按钮 '不得写成new 按钮的形式
  2. Sub 增加我的按钮()
  3. Dim x As CommandBar
  4. Dim m As CommandBarButton
  5. Dim n As CommandBarButton
  6. Set ButtonEvents = New Collection
  7. CommandBars("menu bar").Reset
  8. On Error Resume Next
  9.     CommandBars("新工具条").Delete      '放在这里有用
  10. Set x = CommandBars.Add("新工具条", msoBarTop)
  11.     With x
  12.         .Visible = True
  13.     End With
  14.         Set n = x.Controls.Add(Type:=msoControlButton)
  15.         With n
  16.             .Caption = "测试01"
  17.             .Tag = "测试00001"
  18.             .Style = msoButtonIconAndCaption
  19.             .FaceId = 456
  20.         End With
  21. Set b = New 按钮     '必须要有!
  22. Set b.btn = n
  23. ButtonEvents.Add b    '这里的集合必须要有,虽然我还不太明白含义!否则只有最后一个按钮有用,前面的失灵!
  24. Set m = CommandBars("menu bar").Controls.Add(1)
  25.     m.Caption = "测试02"
  26.     m.Tag = "测试02"
  27.     m.Style = msoButtonIconAndCaption
  28.     m.FaceId = 457
  29. Set b = New 按钮
  30. Set b.btn = m
  31. ButtonEvents.Add b
  32. Set m = CommandBars("menu bar").Controls.Add(1)
  33.     m.Caption = "测试03"
  34.     m.Tag = "测试03"
  35.     m.Style = msoButtonIconAndCaption
  36.     m.FaceId = 453
  37. Set b = New 按钮
  38. Set b.btn = m
  39. ButtonEvents.Add b
  40. End Sub
复制代码
*****************优化代码**************************
  1. 上面的例子中我创建了三个按钮,两个在菜单栏,一个在自定义工具栏,但是每个都需要一堆相似的代码。故写个公共子函数来实现简化:
  2. Function 增加按钮(工具栏名$, 按钮名$, 图标号#)
  3. Set m = CommandBars(工具栏名).Controls.Add(1)
  4.     m.Caption = 按钮名
  5.     m.Tag = 按钮名
  6.     m.Style = msoButtonIconAndCaption
  7.     m.FaceId = 图标号
  8. Set b = New 按钮
  9. Set b.btn = m
  10. ButtonEvents.Add b
  11. End Function
复制代码
  1. 原来的很长的一篇代码就能简化为下面的形式:
  2. Sub 增加我的按钮()
  3. Dim x As CommandBar
  4. Dim m As CommandBarButton
  5. Dim n As CommandBarButton
  6. Set ButtonEvents = New Collection
  7. CommandBars("menu bar").Reset
  8. On Error Resume Next
  9. CommandBars("新工具条").Delete      '放在这里有用
  10. CommandBars.Add("新工具条", msoBarTop).Visible = True
  11. 增加按钮 "新工具条", "测试01", 456
  12. 增加按钮 "menu bar", "测试02", 457
  13. 增加按钮 "menu bar", "测试03", 453
  14. End Sub
复制代码
到这里就差不多了,噢,还差一个弹出式菜单按钮msoControlPopup,下面加上去:
  1. Function 弹出菜单增加按钮(工具栏名$, 弹出菜单$, 按钮名$, 图标号#)
  2. Set m = CommandBars(工具栏名).Controls(弹出菜单).Controls.Add(1)
  3.     m.Caption = 按钮名
  4.     m.Tag = 按钮名
  5.     m.Style = msoButtonIconAndCaption
  6.     m.FaceId = 图标号
  7. Set b = New 按钮    '必须要有!
  8. Set b.btn = m
  9. ButtonEvents.Add b   '这里的集合必须要有,虽然我还不太明白含义!否则只有最后一个按钮有用,前面的失灵!
  10. End Function
复制代码
********************原代码修改如下*******************************

  1. Sub 增加我的按钮()
  2. Dim x As CommandBar
  3. Dim m As CommandBarButton
  4. Dim n As CommandBarButton
  5. Set ButtonEvents = New Collection
  6. CommandBars("menu bar").Reset
  7. On Error Resume Next
  8. CommandBars("新工具条").Delete      '放在这里有用
  9. CommandBars.Add("新工具条", msoBarTop).Visible = True
  10. '-------------------------------------------------------------------
  11. Set pb = CommandBars("新工具条").Controls.Add(Type:=msoControlPopup)
  12.      pb.BeginGroup = True
  13.      pb.Caption = "我的菜单2"
  14. 增加按钮 "新工具条", "测试01", 456
  15. 增加按钮 "menu bar", "测试02", 457
  16. 弹出菜单增加按钮 "新工具条", "我的菜单2", "测试03", 453
  17. End Sub
复制代码
最终如下图所示:
004.png

启动word后就能看到word中出现了按钮。

接下来是为按钮增加相应的功能。



003.png

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:19 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-24 14:16 编辑

为按钮增加功能:
  1. Sub 测试01()
  2.     MsgBox "这是按钮测试——测试01!!!"
  3. End Sub
  4. Sub 测试02()
  5.     MsgBox "这是按钮测试——测试02!!!"
  6. End Sub
  7. Sub 测试03()
  8.     MsgBox "这是按钮测试——测试003!!!"
  9. End Sub
复制代码
类模块部分提供点击按钮后的相应事件
代码如下:
  1. Public WithEvents btn As CommandBarButton

  2. Private Sub btn_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
  3.     Select Case Ctrl.Caption
  4.         Case "测试01"
  5.         测试01
  6.         Case "测试02"
  7.         测试02
  8.         Case "测试03"
  9.         测试03
  10.     End Select

  11. End Sub
复制代码
这个方法源自fanjy版主,是我测试的三种方法中最为简洁的一个了。不过类模块这里感觉还能再优化,不过能力所及,我没想出来。如果不能动态调用的话,有100个sub过程,就需要100个case。如果哪位朋友知道更好的方法,可提供学习下。
这样的话,每个按钮就有偶相应功能了。
附件如下:
成功的加载项.rar (15.29 KB, 下载次数: 274)
下面是更加完善的工具条:
003.png
这里我将之前的代码大部分都加了进去,足以代表各种情况了。
还加入个图片另存为的代码,不过不太稳定。
在试图将vba自动生成现有代码的功能加进去时,失败了。而且发现,一旦失败后,其他按钮都会失效。不知什么原因。
而且还发现,做成COM加载项后,即使没有on error resume next这一句,也不会弹出错误对话框。
由于代码部分太长,就直接上附件了:
最终的com加载项:
成功的加载项.rar (43.38 KB, 下载次数: 337)
加载后不但生成新的工具条,而且包含了弹出式按钮,改变右键菜单,在菜单栏增加按钮等,全部都有。
可以直接作为工具使用了。
接下来是最后一种封装方法:IDTExtensibility2接口

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:20 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-24 14:46 编辑

IDTExtensibility2接口

这里就和上面的方法相似多了。只不过写法方面稍有差异,同样的例子,守柔的第一个加载项就是采用这样的方法:[原创] 我的第一个COM加载项习作
【原以为是靠.net平台制作的,后来研究才发现和.net没半毛钱的关系,vb6.0完全能做。】
不过原理基本一样,不过我采用不一样的写法,可对比上面的方法,看看差异。个人觉得这个写法是比较笨的写法,完全不如上面的写法精炼。
AddinInstance接口是选择加载项后默认的接口,而IDTExtensibility2接口需要引入才能用。而且比前者多了几行没啥意义的代码。不明白到底比前者先进在什么地方。

使用前先引用:
Implements IDTExtensibility2
有了这句后就能看到其的身影了:
001.jpg
和AddinInstance接口相似,我们可以点右侧下列菜单去自动生成一些代码:
002.jpg
生成后我们只需在_OnDisconnection和_OnConnection部分修改即可。前者是断开连接【添加删除工具栏的代码】和开始连接【添加增加按钮的代码】:
  1. Private Sub IDTExtensibility2_OnConnection(ByVal Application As Object, ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)
  2. Set wd = Application
  3. 增加我的按钮
  4. End Sub

  5. Private Sub IDTExtensibility2_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, custom() As Variant)
  6.      x.Delete
  7. Set cbn1 = Nothing
  8. Set cbn2 = Nothing
  9. Set cbn3 = Nothing
  10. Set cbn4 = Nothing
  11. Set wd = Nothing
  12. End Sub

复制代码
COnnect连接器部分完整代码如下:
  1. Implements IDTExtensibility2
  2. Public x As Office.CommandBar
  3. Public WithEvents wd As Word.Application
  4. Public WithEvents cbn1 As CommandBarButton '带事件的按钮
  5. Public WithEvents cbn2 As CommandBarButton '带事件的按钮
  6. Public WithEvents cbn3 As CommandBarButton '带事件的按钮
  7. Public WithEvents cbn4 As CommandBarButton '带事件的按钮
  8. Private Sub IDTExtensibility2_OnAddInsUpdate(custom() As Variant)
  9. End Sub
  10. Private Sub IDTExtensibility2_OnBeginShutdown(custom() As Variant)
  11. wd.CommandBars("新工具条").Delete      '放在这里有用
  12. MsgBox "将要关闭word"
  13. End Sub
  14. Private Sub IDTExtensibility2_OnStartupComplete(custom() As Variant)
  15. End Sub
  16. '上面的三句空过程是调试时提示要求有的,都是自动生成的。没啥意思。
  17. Private Sub IDTExtensibility2_OnConnection(ByVal Application As Object, ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)
  18. Set wd = Application
  19. 增加我的按钮
  20. End Sub

  21. Private Sub IDTExtensibility2_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, custom() As Variant)
  22.      x.Delete
  23. Set cbn1 = Nothing
  24. Set cbn2 = Nothing
  25. Set cbn3 = Nothing
  26. Set cbn4 = Nothing
  27. Set wd = Nothing
  28. End Sub

  29. '可以看到,基本和addininstance是一样的。
  30. Sub 增加我的按钮()

  31. Dim cbn As CommandBar
  32. Set ButtonEvents = New Collection
  33. CommandBars("menu bar").Reset
  34. On Error Resume Next
  35. wd.CommandBars("新工具条").Delete      '放在这里有用
  36. Set x = wd.CommandBars.Add("新工具条", msoBarTop, , 1)
  37. x.Visible = True
  38. '-------------------------------------------------------------------
  39. Set pb = wd.CommandBars("新工具条").Controls.Add(Type:=msoControlPopup)
  40.      pb.BeginGroup = True
  41.      pb.Caption = "我的菜单"
  42.      Set cbn1 = wd.CommandBars("新工具条").Controls("我的菜单").Controls.Add(1)
  43.      cbn1.Caption = "测试按钮1"
  44.      cbn1.Tag = "测试按钮1"
  45.      cbn1.FaceId = 456
  46.      Set cbn2 = wd.CommandBars("新工具条").Controls.Add(1)
  47.      cbn2.Caption = "测试按钮2"
  48.      cbn2.Tag = "测试按钮2"
  49.      cbn2.FaceId = 459
  50.      Set cbn3 = wd.CommandBars("新工具条").Controls.Add(1)
  51.      cbn3.Caption = "测试按钮3"
  52.      cbn3.Tag = "测试按钮3"
  53.      cbn3.FaceId = 465
  54.      Set cbn4 = wd.CommandBars("新工具条").Controls.Add(1)
  55.      cbn4.Caption = "窗体测试"
  56.      cbn4.Tag = "窗体测试"
  57.      cbn4.FaceId = 467
  58.      

  59. End Sub
  60. Sub 去除我的按钮()

  61.     wd.CommandBars("新工具条").Delete
  62. End Sub
  63. Private Sub cbn1_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
  64.     测试按钮1
  65. End Sub

  66. Private Sub cbn2_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
  67.     测试按钮2
  68. End Sub
  69. Private Sub cbn3_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
  70.     Selection.TypeText "这是个测试03!"
  71.     MsgBox "当前文档名为:!" & ActiveDocument.Name & "路径为:" & ActiveDocument.FullName _
  72.     & "共有字数为:" & ActiveDocument.Range.Characters.Count
  73. End Sub
  74. Private Sub cbn4_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
  75. MsgBox "即将显示窗体!"
  76. 批量设定目录.Show 0
  77. End Sub
  78. Sub 测试按钮1()
  79.     Selection.TypeText "这是个测试!"
  80. End Sub
  81. Sub 测试按钮2()
  82.     Selection.TypeText "这是个测试02!"
  83.     MsgBox "你点击了测试按钮二!"
  84. End Sub
复制代码
首先定义带事件的按钮。注意事件这个东西,在标准模块是用不成的,只能在连接器和类模块中使用。还是上面所说的,COM生成的按钮如果不安排事件的话,是用不成的。【这个和vba自动生成的不同,vba在word界面生成 的按钮只需有onaction方法即可。】
此外本人在此处还加入了一个自己做的批量生成目录的窗体,可以看看是如何运作的。
至于窗体的引入,其实很简单,现在word中做好,调试成功后,导出来,再在vb中引入即可,如下窗口:
003.jpg


引入后需要修改下代码,自然就是和前面的ActiveX dll类模块中的修改是完全一样的,不再重复赘述。

005.jpg
006.jpg
007.jpg
附件如下:
IDTExtensibility2测试-02.rar (31.11 KB, 下载次数: 208)
OK了,到这里基本就大功告成了,生成了dll,下一步就是繁琐的调试 →修改再编译 →调试.....直至成功。
总的来说,感觉将vba代码封装为dll比预想的更简单。原来以为需要对现有代码大动刀戈,现在看来98%的vba代码都不需要修改,唯一要做的就是:
将VBA代码批量查找替换下关键词,然后装进VB的”壳“里就行了。我们需要的就是知道如何去制作这个”壳“。
生成dll后进入下一步,制作安装程序。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:23 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-24 15:05 编辑

发布dll的方法
不制作安装包的方法
搞两个批处理文件:安装.bat和卸载.bat
安装.bat :
copy myaddin.dll %windir%\system32\
regsvr32 %windir%\system32\myaddin.dll
卸载.bat
Regsvr32 /u %windir%\system32\myaddin.dll
不过更为方便的还是制作安装包
制作安装包的三种方法

1.winrar制作自解压程序; 001.png
2.使用wise install system制作安装程序 002.png
3. 使用setupfactory制作安装程序 003.png
使用winrar制作安装程序
右键dll文件,添加到压缩文件…
右侧选中创建自解压格式压缩文件
点高级选项卡——自解压选项:
常规:设置解压路径,随便输入如123,选中在当前文件夹中创建;
设置:这里最重要,输入
regsvr32 IDTExtensibility2测试.dll
尝试下面的失败了:
cmd /c copy 123\IDTExtensibility2测试.dll %windir%
regsvr32 %windir%\IDTExtensibility2测试.dll
或者这样填写:
常规里的路径:c:\windows\system32,绝对路径
设置中,解压后运行:regsvr32 IDTExtensibility2测试.dll
其他设置:
文本和图标,和设置解压窗口左侧的蓝色图片bmp,设置解压缩文件的图标,不是默认的书状图标,不过这些都是属于修饰性的东西,无关大碍。
要添加文件,则需要点击文件选项卡,继续添加即可。
缺点:只能安装不能卸载。需要手动卸载。
或者使用前面的批处理文件删除掉。

相关图片:
001.png
004.png
003.png
002.png
006.png
005.png

至此,可生成exe格式的自解压程序。
原理其实就是相当于:先解压到windows\system32文件夹,然后注册。就这么简单。
但是此方法只能安装上去,无法卸载掉。


下面是用专业的安装程序制作软件来搞....

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:24 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-24 15:14 编辑

使用wise install system9.2制作
不得不承认我在研究这个软件的时候非常的不顺利。到现在我也没有探索出如何卸载。
软件一步步设置后会生成安装代码,类似编程代码一样的东西,
如下:
  1. item: Remark
  2.   Text=当您创建一个新安装程序时,如果不想出现Rem(注释)段,
  3. end
  4. item: Remark
  5.   Text=请从 Wise 应用程序目录的 Template 子目录中打开文件 空工程.wse,
  6. end
  7. item: Remark
  8.   Text=删除 Rem 语句,并从文件菜单选择保存。
  9. end
  10. item: Open/Close INSTALL.LOG
  11.   Flags=00000001
  12. end
  13. item: Remark
  14. end
  15. item: Remark
  16.   Text=如果目标系统不具有可写的 Windows\System 目录,系统文件将被写入 Windows\ 目录
  17. end
  18. item: Check if File/Dir Exists
  19.   Pathname=%SYS%
  20.   Flags=10000100
  21. end
  22. item: Set Variable
  23.   Variable=SYS
  24.   Value=%WIN%
  25. end
  26. item: End Block
  27. end
  28. item: Remark
  29. end
  30. item: Remark
  31.   Text=APPTITLE 变量是安装程序应用程序的标题
  32. end
  33. item: Set Variable
  34.   Variable=APPTITLE
  35.   Value=IDTExtensibility2
  36.   Flags=10000000
  37. end
  38. item: Remark
  39. end
  40. item: Remark
  41.   Text=GROUP 变量是位于开始菜单控制快捷方式将放入的程序文件组
  42. end
  43. item: Set Variable
  44.   Variable=GROUP
  45.   Flags=10000000
  46. end
  47. item: Remark
  48. end
  49. item: Remark
  50.   Text=DISABLED 变量被初始化以向后兼容
  51. end
  52. item: Set Variable
  53.   Variable=DISABLED
  54.   Value=!
  55. ................................
复制代码
看起来很奇怪的编程语言,汉语都掺杂进去了。莫非是易语言?看起来真是不如看英文舒服...
使用:选择安装专家,按照坐标的顺序一个一个设置即可。
产品详细资料中设置默认安装路径。很奇怪,我设置了windows,却安装到了windows\system32文件夹中。
卸载需要设置,但是无论我如何设置,都无法删除上面的dll文件。
对话框需要设置,设置安装过程中哪些是不需要的对话框。
感觉主要就是这些,设置好后点击编译,就能生成exe。但是安装后不知道如何卸载掉。即使点击了控制面板中的安装删除程序也没有用。
相关图片:
002.png
003.png
0041.png
生成的程序附件如下:
Wise.rar (568.83 KB, 下载次数: 148)
凑合着能用。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-10-23 16:24 | 显示全部楼层
本帖最后由 zhanglei1371 于 2014-10-25 13:17 编辑

使用setupfactory 7.0制作安装包
这个是这三个里面最令我满意的一个了。既能安装上去,又能卸载掉。而且能在开始菜单中生成相应快捷键方式。非常完美。

尤其是卸载方面,这是在上面两个方法中我没有研究出来的。【或许上面有解决的方法,不过我没发现。】
操作步骤图片如下:

001.jpg 002.jpg
003.jpg
004.jpg
005.jpg
006.jpg
007.jpg



file:///c:/documents and settings/administrator/application data/360se6/User Data/temp/2820942216611684767.png
file:///c:/documents and settings/administrator/application data/360se6/User Data/temp/6619334877118907485.png


点击构建或直接F7即可生成安装程序文件。安装后直接会在开始菜单生成快捷方式,卸载非常方便。
附件:
IDTExtensibility2测试.rar (522.08 KB, 下载次数: 334)
到此为止,我的VBA封装学习过程就结束了。发帖子倒真是浪费了不少时间。。。。
不过,个人认为,封装,对于我而言主要是便于给哪些完全不懂编程不熟悉电脑的人来用,很方便。至于保护代码,没有必要。因为每个人都有自己的编程思想和编程风格,别人是学不去的。水平高的人不会去看你的代码,水平低的人即使是看也看不懂。
而且,假如每个人都把自己的得意代码封装成dll,都不让别人看的话,那么论坛就无法继续发展了。我的vba早期的学习资源多来自守柔和sylun,感谢这二位对word板块的贡献!
因此,衷心希望懂得写代码的人都能将自己的一部分,哪怕是一小部分比较有价值的代码无私放出来,让大家都学习下,这样方能促进论坛的进步!


file:///c:/documents and settings/administrator/application data/360se6/User Data/temp/6619334877118907485.png





您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-21 18:59 , Processed in 0.055338 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表