5

我正在尝试从 VBScript 调用我用 C# 编写的方法。

我已经遵循了我可以在网上找到的所有说明,但仍然遇到问题。

具体来说,我得到

错误:ActiveX 组件无法创建对象

代码:800A01AD

到目前为止,我已经完成了以下工作:

  1. ComVisible(true)
  2. 注册使用regasm /codebase
  3. 强命名我的程序集
  4. 确认它在注册表中并指向正确的位置
  5. 公开班级
  6. 没有静态方法
  7. 制作了我想公开的方法
  8. 有一个无参数的构造函数
  9. 显式定义 GUID

我的 VBScript 看起来像这样:

set oObject = CreateObject("TTTTTT.FFFFF.CCCCCCCCC")

我的 C# 代码如下所示:

using System;
using System.IO;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace XXXXX.YYYYY
{
    [ComVisible(true)]
    [Guid("3EB62C37-79BC-44f7-AFBD-7B8113D1FD4F")]
    [ProgId("TTTTTT.FFFFF.CCCCCCCCC")]
    public class CCCCCCCCC
    {
        public void MyFunc()
        {
            //
        }
    }
}

任何人都可以帮忙吗?

4

5 回答 5

4

你读过这篇文章吗: COM Interop Exposed

在文章的最后一页(3)中,有一个列表:

  1. 为要公开给 COM 的方法定义一个 .NET 接口。
  2. 使用“Guid”属性为该接口分配一个 GUID。
  3. 让你的类实现你的接口作为第一个接口。
  4. 使用“Guid”属性为该类分配一个 GUID。
  5. 添加“ ClassInterface(ClassInterfaceType.None)”属性以防止 regasm/tlbexp 创建空的默认接口。
  6. 在您的 AssemblyVersion 属性中硬编码特定版本号。
  7. 为您的程序集创建一个强名称密钥对,并通过 AssemblyKeyFile 属性指向它。
  8. 将您的程序集添加到 GAC,
  9. 使用 REGASM 命令和“/tlb”选项为 COM 注册程序集,以生成 COM 类型库。

我不确定 GACClassInterfaceType.None是否是您拼图中缺失的部分,您可能想尝试一下。祝你好运!

于 2009-11-14T03:59:56.767 回答
4

您的代码没有任何问题,并且您遵循了正确的安装过程,听上去是这样。然而,您得到的错误代码清楚地表明脚本解释器无法定位或加载程序集。解决此问题的最佳方法是使用 SysInternals 的 ProcMon 实用程序。

我毫无问题地运行了您的代码,这些是 ProcMon 日志中最相关的条目:

22  12:04:41.1795038 PM WScript.exe 55280   RegOpenKey  HKCR\TTTTTT.FFFFF.CCCCCCCCC SUCCESS Desired Access: Read
26  12:04:41.1795682 PM WScript.exe 55280   RegOpenKey  HKCR\TTTTTT.FFFFF.CCCCCCCCC\CLSID   SUCCESS Desired Access: Read
29  12:04:41.1796996 PM WScript.exe 55280   RegQueryValue   HKCR\TTTTTT.FFFFF.CCCCCCCCC\CLSID\(Default) SUCCESS Type: REG_SZ, Length: 78, Data: {3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}
34  12:04:41.1797653 PM WScript.exe 55280   RegOpenKey  HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}   SUCCESS Desired Access: Read
62  12:04:41.1802539 PM WScript.exe 55280   RegOpenKey  HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32    SUCCESS Desired Access: Read
71  12:04:41.1804181 PM WScript.exe 55280   RegQueryValue   HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32\(Default)  SUCCESS Type: REG_SZ, Length: 24, Data: mscoree.dll
824 12:04:41.2425662 PM WScript.exe 55280   RegQueryValue   HKCR\CLSID\{3EB62C37-79BC-44F7-AFBD-7B8113D1FD4F}\InprocServer32\1.0.0.0\CodeBase   SUCCESS Type: REG_SZ, Length: 124, Data: file:///c:/projects/ClassLibrary2/obj/Debug/ClassLibrary2.DLL
... Lots of .NET keys...
1239    12:04:41.2970169 PM WScript.exe 55280   CreateFile  C:\projects\ClassLibrary2\obj\Debug\ClassLibrary2.dll   SUCCESS Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
于 2009-11-14T18:19:13.000 回答
2

这是一个简单的项目,只需几个步骤即可帮助您入门。

C#代码:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly:System.CLSCompliant(true)]
[assembly: ComVisible(true)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b0")]

namespace Cheeso.ComTests
{
    [Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b1")]
    public class TestReply
    {
        public string salutation;
        public string name;
        public string time;
    }

    [Guid("7d9c5cd3-73d4-4ab1-ba98-32515256c0b2")]
    public class TestObj
    {
        // ctor
        public TestObj () {}

        public TestReply SayHello(string addressee)
        {
            return SayHello(addressee, "hello");
        }

        public TestReply SayHello(string addressee, string greeting)
        {
            string x = String.Format("{0}, {1}!", greeting, addressee);
            Console.WriteLine("{0}", x);

            TestReply r = new TestReply
            {
                salutation = greeting,
                name = addressee,
                time = System.DateTime.Now.ToString("u")
            };
            return r;
        }
    }
}

VBScript 客户端代码:

Function Main()
    Dim obj
    Dim reply
    set obj = CreateObject("Cheeso.ComTests.TestObj")
    Set reply = obj.SayHello("Evgeny")
    WScript.Echo "Reply at: " & reply.time
    Set reply = obj.SayHello_2("Evgeny", "wassup")
    WScript.Echo "Reply at: " & reply.time
End Function

Main

构建:

(produce your .snk file, once)
csc.exe /t:library /debug+ /keyfile:Foo.snk /out:TestObj.dll TestObj.cs
regasm /codebase TestObj.exe

然后只需运行 vbscript(通过 cscript.exe)。

一旦你让基本的东西工作起来,你可以调整它,添加 GAC,使 typelib 显式,添加显式 ProgId,等等。

ps:仅供参考,此示例显示了在为互操作注册的类上重载 .NET 方法会发生什么。方法名称后附加了一个隐式 _2(_3、_4 等)。

于 2009-11-14T13:35:00.780 回答
1

要使 Cheeso 的示例在 64 位平台上运行,请确保调用 CScript.exe:

%windir%\SysWOW64\cscript.exe test.vbs

参考:不能在 Windows 7 x64 上使用 VB 脚本中的 CreateObject

于 2013-10-27T14:30:52.320 回答
0

可能,你所有的问题都是VS引起的。尝试通过键入从命令行编译您的库

csc.exe /t:library AClass.cs /keyfile:Foo.snk - produce your key file with VS!
regasm /codebase /tlb AClass.dll

VS正在添加一些诸如/warn: /noconfig之类的东西,并且它还添加了对System.Core等其他程序集的引用,有时会导致错误。对我来说,从 csc 编译是有效的。

于 2009-12-17T08:34:26.203 回答