代码之家  ›  专栏  ›  技术社区  ›  melaos

如何通过COM/VB6将参数传递给.NET DLL中的函数?

  •  3
  • melaos  · 技术社区  · 16 年前

    我有一个用C编写的.NET DLL,它从数据源中读取数据,并充当一个包装器,允许其他应用调用它的函数来检索这些数据。问题是,我没有预料到.NET dll会被用于.NET应用程序以外的其他应用程序,所以现在我被告知这一切都将被用于vba/powerpoint宏中,我认为它与vb6应用程序非常相似,所以这就是我现在计划测试它的方式。

    通过谷歌搜索,甚至在这里发布了一些问题,我设法让动态链接库在vb6内部被引用,但是当我试图调用一个有任何参数的函数时,我会得到错误的运行时消息:错误的参数数目450或无效的属性分配。

    问题

    我做错了什么?另外,是否可以有人提供一些资源或示例代码,以便我了解如何正确地编写一个.NET dll,它具有可以从vb6/vba应用程序调用的参数函数?

    如果我的代码有点凌乱以至于看不懂的话:),那么也许你们可以帮我告诉我如何使用参数。 this sample which i learn from codeproject ,当我在其中包含一些参数时,它将返回相同的错误消息。

    更新:

    i found another set of sample codes here 但不幸的是,它只将参数作为整数传递,当我尝试执行一个将参数作为字符串传递的示例函数时,我得到了相同的错误。我是否遗漏了一些基本的东西?有人想烧个Noobie吗?

    更新2:

    为了防止有其他人偶然发现这个问题,我没有真正找出导致这个问题的原因或原因,但是由于这个项目仍然很小,我只是使用了一个DLL的工作示例,它能够正确地返回字符串并开始将每个函数的函数移到它上面,现在它工作得很好:)

    谢谢!!!!

    .NET DLL代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Configuration;
    using System.Data.OleDb;
    using System.Data;
    using System.Xml;
    using System.Xml.Linq;
    using System.IO;
    using System.Security;
    using System.Security.Cryptography;
    using System.Runtime.InteropServices;
    //using System.Windows.Forms;
    
    namespace DtasApiTool
    {
    
        [Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7040")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        public interface _Program
        {
            [DispId(1)]
            string Get_All_Locales(string test);
    
            [DispId(2)]
            string Get_All_Levels(string locale);
    
            [DispId(3)]
            string Get_Subjects_ByLocaleLevelId(string locale, int levelId);
    
            [DispId(4)]
            string Get_Topic_ByLevelIdLocaleSubjectId(int levelId, string locale, int subjectId);
    
            [DispId(5)]
            string Get_Subtopic_ByLevelIdLocaleSubjectIdTopicId(int levelId, string locale, int subjectId, int topicId);
    
            [DispId(6)]
            string Get_Skill_ByLevelIdLocaleSubjectIdTopicIdSubtopicId(int levelId, string locale, int subjectId, int topicId, int subtopicId);
    
            [DispId(7)]
            string Get_All_Subjects(string locale);
    
            [DispId(8)]
            void Constructor(string directory);
    
        }
    
        [Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA5")]
        [ClassInterface(ClassInterfaceType.None)]
        [ProgId("DtasApiTool.Program")]
        public class Program : _Program
        {
            private string connStr = "";
            private string xmlLocation = "";
    
            public Program(){
    
            }
    
            public void Constructor(string directory)
            {
              ...  
            }
    
    
            #region This part contains all the internal functions
    
            /// <summary>
            /// return the component lesson given a locale and skill id
            /// </summary>
            /// <param name="locale"></param>
            /// <param name="skillId"></param>
            /// <returns></returns>
            internal string Get_Component_Lesson(string locale, string skillId)
            {
                ...
            }
    
            /// <summary>
            /// return a xmlFile containing all the information from the Skill Analysis
            /// </summary>
            /// <param name="fileLocation">raw xml file location, i.e. C://datapath/raw_dato.xml</param>
            /// <returns> the location of the output xml file.</returns>
            internal string Process_Skill_Analysis_Report(string fileLocation)
            {            
    ...
    }
    
            #endregion
    
            /// <summary>
            /// Returns all the locale which is in the database currently.
            /// </summary>
            /// <returns></returns>
            public string Get_All_Locales(string test)
            {
            ...
            }
    }
    

    这就是我从vb6调用它的方式:

    Option Explicit
    
    Private Sub Form_Load()        
        Dim obj As DtasApiTool.Program
        Set obj = New DtasApiTool.Program
    
        Dim directory As String
        directory = """" + "C:\Documents and Settings\melaos\My Documents\Visual Studio 2008\Projects\app\bin\Release\" + """"
    
        'obj.Constructor directory
        Dim func As String
       func = obj.Get_All_Locales(directory)
    
    End Sub
    
    4 回复  |  直到 16 年前
        1
  •  2
  •   C-Pound Guru    16 年前

    我注意到你不见了 [ComVisible(true)] .

    接口头应如下所示:

    [Guid("CF4CDE18-8EBD-4e6a-94B4-6D5BC0D7F5DE")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [ComVisible(true)]
    public interface IFoo {
    
        [DispId(1)]
        string MyMethod(string value);
    }
    

    类标题应如下所示:

    [Guid("7EBD9126-334C-4893-B832-706E7F92B525")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    [ProgId("MyNamespace.Foo")]
    public class Foo: IFoo {
    
        public string MyMethod(string value){
            return somestring;
        }
    }
    
        2
  •  1
  •   AnthonyWJones    16 年前

    尝试更改此代码块:

    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    

    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    

    我不知道为什么会出现错误,但您的vb6代码似乎正在尝试早期(或vtable)绑定,但是 InterfaceIsIDispatch 不支持。它可能是vb6本身返回到后期绑定,但为什么您希望它?

    此外,如果您真的需要模拟现有的COM接口,那么还可以删除它们所需要的所有dispid属性。

        3
  •  1
  •   Eric Nicholson    16 年前

    我相信Dispid(1)是为字符串或类似的内容保留的(已经有一段时间了) 尝试在2点启动DispID。

        4
  •  1
  •   Andreas F    16 年前

    导出/注册程序集后,是否尝试查看类型库(使用oleview.exe)?

    我的怀疑是,所有方法都返回字符串,而COM方法倾向于返回hresult(不知道这通常是真的-实际上,您的示例代码项目页似乎另有建议),这意味着您需要将输入和输出放入方法参数中,并用[in]、[out]和/或[retval]显式地封送它们。

    无论如何,看看类型库并检查它是否像您期望的那样。如果不是,则可能必须使用marshalas属性显式封送类型。

    推荐文章