Board logo

标题: [原创] 如何制作com组件 [打印本页]

作者: jyswjjgdwtdtj    时间: 2024-7-12 15:01     标题: 如何制作com组件

本帖最后由 jyswjjgdwtdtj 于 2024-7-15 16:39 编辑

受制于微软对vbs安全性的考量 vbs只能使用com组件与电脑交互
远古时期有人很喜欢用vb6制作com vb6对于com极其支持 你甚至可以不用写出class的关键字
而用c++等底层语言则工作量就较为恐怖 借口等等均要手动实现
那如何创建com组件呢?

所需材料:一台安装有.net framework(win7及以上基本均有安装)的windows电脑  无需visual studio
编写com组件使用vb.net语言

需要明确一点,vbs是一项基于com组件的语言,换句话说vbs中的任何一个对象均为com对象,且vbs只支持符合com规范的对象。若你将vbs中声明的类对象传入.net .net会告诉你那是System.__ComObject
类型 所以请勿将.net中的对象直接返回至vbs,vbs不支持的泛型,枚举等等会使对象不可用

首先介绍一下vb.net
vbs作为vb家族的一员,在语法上基本是vb6的真子集。而在vb.net中,为了适应更现代化的面向对象,vb.net添加了接口,继承等等内容,同时对于类的结构做出了调整
vb.net的程序结构为
  1. namespace vbnamespace '命名空间
  2. module vbmodule '模块 可以直接理解为静态类
  3. class vbclass '类
  4. public a as string'变量
  5. public sub new()'构造函数
  6. end sub
  7. public property ppt
  8. get
  9. end get
  10. set
  11. end set
  12. end property
  13. end class
  14. end module
  15. end namespace
复制代码
有兴趣可以自行学习(但似乎c#远更为流行

编写com组件首先需要引入命名空间,可以理解为载入别人写好的函数
准备好程序内容所在的namespace namespace名字为com组件progid的前半部分
这一部分可以无脑照抄
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Namespace progid_NamespaceName
  4. End Namespace
复制代码
添加一个接口
为它打上标签
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Namespace progid_NamespaceName
  4.     <ComVisible(True)>
  5.     <Guid("yourguid")>'guid可以用工具生成
  6.     <InterfaceType(ComInterfaceType.InterfaceIsDual)>
  7.     Public Interface IComExample
  8.         '这里写入函数声明 如
  9.         '每个函数 变量均必须在接口中声明 否则不能被外部使用
  10.         Function tostring(obj as object) As string
  11.         Public strname as string
  12.         'Sub mysub(abc As paramtype) As returntype
  13.     End Interface
  14. End Namespace
复制代码
然后制作com对象
com对象的主体部分为一个类
  1.     Public Class progid_ClassName
  2. '必将其设置为public 名字为progid的后半部分
  3.         Implements IComExample'继承接口 必须要加
  4.         Public Function tostring(obj as object) As string Implements IComExample.tostring
  5.         '实现接口中的函数 implements语句代表着这个函数是接口中的函数
  6.             Return Convert.ToString(obj)
  7.             '相当于
  8.             'tostring=Convert.ToString(obj)
  9.             'exit function
  10.         End Function
  11.         Public str as string="string"
  12.     End Class
复制代码
只有继承了接口的类可以被外部创建
将主体对象添加进
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Namespace vbcom
  4.     <ComVisible(True)>
  5.     <Guid("00000000-0000-0000-0000-000000000000")>
  6.     <ClassInterface(ClassInterfaceType.None)>
  7.     Public Interface IComExample
  8.         Function tostring(obj as object) As string
  9.     End Interface
  10.     '也给对象打上标签 guid不能一样
  11.     <ComVisible(True)>
  12.     <Guid("11451419-1981-0114-5141-919810000000")>'注意 与接口中的不一样
  13.     <InterfaceType(ComInterfaceType.InterfaceIsDual)>
  14.     <ProgId(mynewcom.test))>'progid标签可以强制类的progid
  15.     Public Class ComExample
  16.         Implements IComExample
  17.         Public Function tostring(obj as object) As string Implements IComExample.tostring
  18.             Return Convert.ToString(obj)
  19.         End Function
  20.     End Class
  21. End Namespace
复制代码
这是一个clsid为{11451419-1981-0114-5141-919810000000} progid为vbcom.comexample的com组件 包含一个名为tostring的函数 可以将对象转换为字符串

代码编写完成后 将其保存为mycom.vb 接下来进行编译
找到C:\Windows\Microsoft.NET\中版本最新的vbc.exe 用它的路径替换以下路径 或直接使用
建议在编译时使用绝对路径 并将dll保存至system32文件夹
  1. ::bat
  2. "C:\Windows\Microsoft.NET\Framework\v4.0.30319\vbc.exe" /target:library  /out:C:\mycom.dll /platform:anycpu C:\mycom.vb
复制代码
将mycom.vb编译为mycom.dll
  1. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /u C:\mycom.dll
  2. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe C:\mycom.dll /codebase
复制代码
卸载;加载 注意:这一步要管理员权限 请用管理员运行bat
如果你想要修改你的com组件 无需重新使用regasm注册 只需用新的com组件dll将原本的替代掉即可

如果任何一个步骤没有报错 那com组件就可以用了
  1. set myfirstcom=createobject("vbcom.comexample")
  2. msgbox myfirstcom.tostring(123)
复制代码
然后你就可以制作属于自己的com组件了!

可以在同一个命名空间下有多个com类 可以重复interface-class一一对应
作者: buyiyang    时间: 2024-7-12 20:01

感谢详尽的分享!
可能有笔误,第一段代码接口和类的类型说明写反了哦,第二段代码类没有绑定接口实现
作者: czjt1234    时间: 2024-7-12 21:39

不明觉厉          .
作者: jyswjjgdwtdtj    时间: 2024-7-13 12:01

回复 2# buyiyang


    第一段已改正 第二段没错呀 没有继承接口的类不公开给com组件
作者: Five66    时间: 2024-7-13 12:02

用.net支持的语言写com确实简单多了
不过写出来的com貌似是基于clr的
还有调第三方是神,都来调第三方吧
作者: jyswjjgdwtdtj    时间: 2024-7-15 16:38

回复 5# Five66


    是的 速度慢
还有自己做第三方给自己用和调别人的第三方还是有点区别的吧
作者: Five66    时间: 2024-7-19 22:22

回复 6# jyswjjgdwtdtj


    自己做第三方给自己用,一般都会力求简单吧, 甚至可能全程在其里面实现,直接运行即可
作者: jyswjjgdwtdtj    时间: 2024-7-20 16:50

回复 7# Five66


其实对于.net里的语言 不如就把他当成一种脚本来使用
powershell实在接受不了
作者: jyswjjgdwtdtj    时间: 2024-8-5 17:06

发个例子
  1. using System.Runtime.InteropServices;
  2. using System.Windows.Forms;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Reflection;
  7. namespace VBScript
  8. {
  9.     [ComVisible(true)]
  10.     [Guid("FD3B7777-90F5-AC77-C8D3-1B5259B42927")]
  11.     [InterfaceType(ComInterfaceType.InterfaceIsDual)]
  12.     public interface IWinForm
  13.     {
  14.         Control GetControl(string controlname);
  15.         void AddControl(object c, object p);
  16.         void AddControl(object c, object[] p);
  17.         Control[] GetControlList(object c);
  18.         void AttachEvent(object c, string eventname, object f);
  19.     }
  20.     [ComVisible(true)]
  21.     [Guid("2A0C7DB1-4CAF-561D-130A-2C52DB0DF12D")]
  22.     [ClassInterface(ClassInterfaceType.None)]
  23.     public class WinForm : IWinForm
  24.     {
  25.         public Control GetControl(string controlname)
  26.         {
  27.             return (Control)typeof(System.Windows.Forms.Form).Assembly.CreateInstance("System.Windows.Forms." + controlname, true);
  28.         }
  29.         public void AddControl(object c, object p)
  30.         {
  31.             ((Control)c).AddControl((Control)p);
  32.         }
  33.         public void AddControl(object c, object[] p)
  34.         {
  35.             ((Control)c).AddControl(p);
  36.         }
  37.         public Control[] GetControlList(object c)
  38.         {
  39.             return ((Control)c).GetControlList();
  40.         }
  41.         public void AttachEvent(object c, string eventname, object f)
  42.         {
  43.             ((Control)c).AttachEvent(eventname, f);
  44.         }
  45.     }
  46.     public static class ExtensionMethodForWinFormInCom
  47.     {
  48.         public static Control[] GetControlList(this Control control)
  49.         {
  50.             IList<Control> list = (IList<Control>)control.Controls;
  51.             return list.ToArray();
  52.         }
  53.         public static void AddControl(this Control p, Control c)
  54.         {
  55.             p.Controls.Add(c);
  56.         }
  57.         public static void AddControl(this Control p, object[] c)
  58.         {
  59.             List<Control> cl = new List<Control>();
  60.             Type ctlt = typeof(Control);
  61.             foreach (object o in c)
  62.             {
  63.                 if (o.GetType() == ctlt)
  64.                 {
  65.                     cl.Add(o as Control);
  66.                 }
  67.             }
  68.             p.Controls.AddRange(cl.ToArray());
  69.         }
  70.         public static void AttachEvent(this Control c, string eventname, object co)
  71.         {
  72.             EventInfo ev = c.GetType().GetEvent(eventname);
  73.             switch (ev.EventHandlerType.Name)
  74.             {
  75.                 case "KeyEventHandler":
  76.                     ev.AddEventHandler(c, new KeyEventHandler((object sender, KeyEventArgs e) =>
  77.                     {
  78.                         ComFuncCaller.Invoke(co, sender, e);
  79.                     }));
  80.                     break;
  81.                 case "KeyPressEventHandler":
  82.                     ev.AddEventHandler(c, new KeyPressEventHandler((object sender, KeyPressEventArgs e) =>
  83.                     {
  84.                         ComFuncCaller.Invoke(co, sender, e);
  85.                     }));
  86.                     break;
  87.                 case "MouseEventHandler":
  88.                     ev.AddEventHandler(c, new MouseEventHandler((object sender, MouseEventArgs e) =>
  89.                     {
  90.                         ComFuncCaller.Invoke(co, sender, e);
  91.                     }));
  92.                     break;
  93.                 case "EventHandler":
  94.                     ev.AddEventHandler(c, new EventHandler((object sender, EventArgs e) =>
  95.                     {
  96.                         ComFuncCaller.Invoke(co, sender, e);
  97.                     }));
  98.                     break;
  99.                 case "PaintEventHandler":
  100.                     ev.AddEventHandler(c, new PaintEventHandler((object sender, PaintEventArgs e) =>
  101.                     {
  102.                         ComFuncCaller.Invoke(co, sender, e);
  103.                     }));
  104.                     break;
  105.                 default:
  106.                     break;
  107.             }
  108.         }
  109.         public static class ComFuncCaller
  110.         {
  111.             public static void Invoke(dynamic o,object sender,dynamic e)
  112.             {
  113.                 (new z(o)).zz(sender,e);
  114.             }
  115.             private struct z
  116.             {
  117.                 public dynamic zz;
  118.                 public z(dynamic zzz)
  119.                 {
  120.                     zz = zzz;
  121.                 }
  122.             }
  123.         }
  124.     }
  125. }
复制代码





欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2