【问题标题】:how to pass parameters to a function in a .net dll via COM/VB6?如何通过 COM/VB6 将参数传递给 .net dll 中的函数?
【发布时间】:2010-11-20 03:11:16
【问题描述】:

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

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

问题

那么我做错了什么?有人可以提供一些资源或示例代码,我可以学习如何正确编写具有可从 vb6/vba 应用程序调用的参数的函数的 .net dll 吗?

如果我的代码有点太乱而无法阅读:),那么也许你们可以帮助告诉我如何在this sample which i learn from codeproject 中使用参数,当我在那里包含一些参数时它会返回相同的错误消息。

更新:

i found another set of sample codes here,但不幸的是它只将参数作为整数传递,当我尝试执行一个将参数作为字符串传递的示例函数时,我得到了同样的错误。我在这里缺少一些基础知识吗?有人在乎烧一个菜鸟吗?

更新 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

【问题讨论】:

    标签: .net com vb6 interop parameter-passing


    【解决方案1】:

    我注意到你不见了[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】:

      尝试更改这段代码:-

      [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
      

      [InterfaceType(ComInterfaceType.InterfaceIsDual)]
      

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

      同时删除所有 DispId 属性,只有在您确实需要模拟现有 COM 接口时才需要它们。

      【讨论】:

      • @Anthony,谢谢,我不再收到错误消息,但我仍然没有从函数中获得任何数据:(
      • @Melaos:至少这是进步;)。我现在建议您编译您的 VB6 应用程序,运行它并将 VS 调试器附加到它。确保您的 .NET dll 中的代码正在执行您认为的操作,并且正在接收您认为的参数。
      • @Anythony,是的,我很高兴至少我可以绕过错误部分,我实际上正在尝试学习如何调试这整个事情,因为我正在使用 vs. net express,我不能做attach调试方法:(
      • 您是否在 VS Express 中单独测试了 .NET?您可以为您的 .NET 组件构建一个 VB6 模型并用它测试您的 VB6 代码吗?
      • @Anthony,我构建了另一个 c# 应用程序来测试 dll,因为我没有意识到 dll 将被 com 应用程序引用 :(,您是否建议我构建vb6中的dll?
      【解决方案3】:

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

      【讨论】:

      • 这不是真的,唯一保留的DispID为0及以下,例如-4用于获取支持For Each的IEnumVariant。
      • 我的错,看起来 ToString 实际上是 _Object 上的 0。谢谢!
      【解决方案4】:

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

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

      无论如何,看看类型库并检查它是否看起来像您期望的那样。如果不是,您可能必须使用 MarshalAs 属性显式编组您的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-04
        • 2012-07-13
        • 2012-05-15
        • 1970-01-01
        • 2011-07-13
        • 2019-06-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多