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

时间:2009-08-17 02:28:28

标签: .net com vb6 interop parameter-passing

我有一个用c#编写的.net dll,它从数据源读取数据并充当包装器,允许其他应用程序调用其函数来检索这些数据。事情是我没有预料到.net dll会被用于除.net应用程序以外的其他内容,所以现在我被告知这一切都将用于vba / powerpoint宏,我认为它与vb6 app非常相似,这就是我现在计划如何测试它。

经过一些谷歌搜索,甚至在这里发布了一些问题,我设法在vb6中引用dll,但是当我尝试调用一个有任何参数的函数时,我会得到错误运行时错误消息450错误的参数数量或无效的属性赋值。

问题

那么我做错了什么?并且有人可以提供一些资源或示例代码,我可以学习如何正确编写.net dll,其功能参数可以从vb6 / vba app调用吗?

如果我的代码有点太杂乱无法阅读:),那么也许你们可以帮忙告诉我如何在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 个答案:

答案 0 :(得分:2)

我注意到你遗失了[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;
    }
}

答案 1 :(得分:1)

尝试更改此代码块: -

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

[InterfaceType(ComInterfaceType.InterfaceIsDual)]

我不确定为什么你会得到错误,但是早期(或VTable)绑定是VB6代码似乎尝试但InterfaceIsIDispatch不支持的。它可能的VB6本身会回落到后期绑定,但你为什么要它呢?

如果您确实需要模拟现有的COM接口,还要删除它们只需要的所有DispId属性。

答案 2 :(得分:1)

我相信DispID(1)是为ToString或类似的东西保留的(已经有一段时间了) 尝试在2开始您的DispID。

答案 3 :(得分:1)

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

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

无论如何,看看类型库并检查它是否看起来像你希望它看起来。如果不是,您可能必须使用MarshalAs属性明确封送您的类型。