传递VBA类的实时实例时,C#ITypeInfo.GetContainingTypeLib失败

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了传递VBA类的实时实例时,C#ITypeInfo.GetContainingTypeLib失败相关的知识,希望对你有一定的参考价值。

所以我已经尝试在VBA类实例上调用ITypeInfo,虽然看起来很有希望但我想看看我是否可以获得对其包含项目的引用,类似于类型库。我认为ITypeInfo.GetContainingTypeLib可能很有用,但它会抛出一个异常,表明VBA不会合作。任何人都对VBA如何采用与标准COM规范不同的东西有任何想法?

C#类库代码在这里。注册COM interop并在AssemblyInfo.cs中设置COMVisible(true)以使其可从VBA访问。下面给出的VBA客户端代码。

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;


namespace TypeLibraryInspector
{
    [ComImport()]
    [Guid("00020400-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDispatch
    {
        [PreserveSig]
        int GetTypeInfoCount(out int Count);

        [PreserveSig]
        int GetTypeInfo
            (
                [MarshalAs(UnmanagedType.U4)] int iTInfo,
                [MarshalAs(UnmanagedType.U4)] int lcid,
                out System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo
            );


        //void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler,
        //        MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo);

        //void GetTypeInfo(int typeInfoIndex, int lcid,  out IntPtr piTypeInfo);


        [PreserveSig]
        int GetIDsOfNames
            (
                ref Guid riid,
                [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
                string[] rgsNames,
                int cNames,
                int lcid,
                [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId
            );

        [PreserveSig]
        int Invoke
            (
                int dispIdMember,
                ref Guid riid,
                uint lcid,
                ushort wFlags,
                ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,
                out object pVarResult,
                ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo,
                IntPtr[] pArgErr
            );
    }


    public interface IInspector
    {
        void InspectThisObject(object vbaClassInstance);
    }

    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(IInspector))]

    public class Inspector : IInspector
    {
        private const int S_OK = 0; //From WinError.h
        private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800



        void IInspector.InspectThisObject(object vbaClassInstance)
        {
            //https://limbioliong.wordpress.com/2011/10/18/obtain-type-information-of-idispatch-based-com-objects-from-managed-code/
            IDispatch pDispatch = (IDispatch)vbaClassInstance;

            ITypeInfo piTypeInfo;
            pDispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out piTypeInfo);

            string s1; string s2; string s3;
            int i1;
            piTypeInfo.GetDocumentation(-1, out s1, out s2, out i1, out s3);
            //s1 = "Class1" good
            //s2 = null     shame

            ITypeLib piTypeLib;
            int pIndex;

            piTypeInfo.GetContainingTypeLib(out piTypeLib, out pIndex); // <-- throws Exception 0x800A88C1

        }
    }
}

所以一些客户VBA就在这里

Sub Test()

    Dim oInspector As TypeLibraryInspector.Inspector
    Set oInspector = New TypeLibraryInspector.Inspector

    Dim oClass1 As Class1
    Set oClass1 = New Class1

    oInspector.InspectThisObject oClass1

End Sub

Class1可以是任何类,我有两个空函数,但我认为不相关。

我问过equivalent C++ question

答案

如果dll是暴露的,则必须在regsvr32中注册

你也可能需要GAC .net程序集

以上是关于传递VBA类的实时实例时,C#ITypeInfo.GetContainingTypeLib失败的主要内容,如果未能解决你的问题,请参考以下文章

为什么VBA的VarType函数说这个COM对象是一个字符串? (Object是.NET的System.Object类的COM版本的实例。)这是一个错误吗?

在 VBA 中初始化无限数量的类:使用变量来命名类的实例

C ++继承:将子类传递给期望基类的函数并获得子类行为

我可以通过 COM 从 VBA 调用 C# 类的静态方法吗?

将不同的函数传递到同一个迭代循环(VBA)

使用 SPOON 创建匿名类的实例