返回列表 发帖

[原创] 如何制作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的程序结构为
namespace vbnamespace '命名空间
module vbmodule '模块 可以直接理解为静态类
class vbclass '类
public a as string'变量
public sub new()'构造函数
end sub
public property ppt
get
end get
set
end set
end property
end class
end module
end namespaceCOPY
有兴趣可以自行学习(但似乎c#远更为流行

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

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

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

可以在同一个命名空间下有多个com类 可以重复interface-class一一对应
3

评分人数

感谢详尽的分享!
可能有笔误,第一段代码接口和类的类型说明写反了哦,第二段代码类没有绑定接口实现

TOP

不明觉厉          .

QQ 20147578

TOP

回复 2# buyiyang


    第一段已改正 第二段没错呀 没有继承接口的类不公开给com组件

TOP

用.net支持的语言写com确实简单多了
不过写出来的com貌似是基于clr的
还有调第三方是神,都来调第三方吧

TOP

回复 5# Five66


    是的 速度慢
还有自己做第三方给自己用和调别人的第三方还是有点区别的吧

TOP

回复 6# jyswjjgdwtdtj


    自己做第三方给自己用,一般都会力求简单吧, 甚至可能全程在其里面实现,直接运行即可

TOP

回复 7# Five66


其实对于.net里的语言 不如就把他当成一种脚本来使用
powershell实在接受不了

TOP

发个例子
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace VBScript
{
    [ComVisible(true)]
    [Guid("FD3B7777-90F5-AC77-C8D3-1B5259B42927")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IWinForm
    {
        Control GetControl(string controlname);
        void AddControl(object c, object p);
        void AddControl(object c, object[] p);
        Control[] GetControlList(object c);
        void AttachEvent(object c, string eventname, object f);
    }
    [ComVisible(true)]
    [Guid("2A0C7DB1-4CAF-561D-130A-2C52DB0DF12D")]
    [ClassInterface(ClassInterfaceType.None)]
    public class WinForm : IWinForm
    {
        public Control GetControl(string controlname)
        {
            return (Control)typeof(System.Windows.Forms.Form).Assembly.CreateInstance("System.Windows.Forms." + controlname, true);
        }
        public void AddControl(object c, object p)
        {
            ((Control)c).AddControl((Control)p);
        }
        public void AddControl(object c, object[] p)
        {
            ((Control)c).AddControl(p);
        }
        public Control[] GetControlList(object c)
        {
            return ((Control)c).GetControlList();
        }
        public void AttachEvent(object c, string eventname, object f)
        {
            ((Control)c).AttachEvent(eventname, f);
        }
    }
    public static class ExtensionMethodForWinFormInCom
    {
        public static Control[] GetControlList(this Control control)
        {
            IList<Control> list = (IList<Control>)control.Controls;
            return list.ToArray();
        }
        public static void AddControl(this Control p, Control c)
        {
            p.Controls.Add(c);
        }
        public static void AddControl(this Control p, object[] c)
        {
            List<Control> cl = new List<Control>();
            Type ctlt = typeof(Control);
            foreach (object o in c)
            {
                if (o.GetType() == ctlt)
                {
                    cl.Add(o as Control);
                }
            }
            p.Controls.AddRange(cl.ToArray());
        }
        public static void AttachEvent(this Control c, string eventname, object co)
        {
            EventInfo ev = c.GetType().GetEvent(eventname);
            switch (ev.EventHandlerType.Name)
            {
                case "KeyEventHandler":
                    ev.AddEventHandler(c, new KeyEventHandler((object sender, KeyEventArgs e) =>
                    {
                        ComFuncCaller.Invoke(co, sender, e);
                    }));
                    break;
                case "KeyPressEventHandler":
                    ev.AddEventHandler(c, new KeyPressEventHandler((object sender, KeyPressEventArgs e) =>
                    {
                        ComFuncCaller.Invoke(co, sender, e);
                    }));
                    break;
                case "MouseEventHandler":
                    ev.AddEventHandler(c, new MouseEventHandler((object sender, MouseEventArgs e) =>
                    {
                        ComFuncCaller.Invoke(co, sender, e);
                    }));
                    break;
                case "EventHandler":
                    ev.AddEventHandler(c, new EventHandler((object sender, EventArgs e) =>
                    {
                        ComFuncCaller.Invoke(co, sender, e);
                    }));
                    break;
                case "PaintEventHandler":
                    ev.AddEventHandler(c, new PaintEventHandler((object sender, PaintEventArgs e) =>
                    {
                        ComFuncCaller.Invoke(co, sender, e);
                    }));
                    break;
                default:
                    break;
            }
        }
        public static class ComFuncCaller
        {
            public static void Invoke(dynamic o,object sender,dynamic e)
            {
                (new z(o)).zz(sender,e);
            }
            private struct z
            {
                public dynamic zz;
                public z(dynamic zzz)
                {
                    zz = zzz;
                }
            }
        }
    }
}COPY

TOP

返回列表