我有一个用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?
以防有其他人偶然发现这个问题,我没有真正找到导致问题的原因或原因,但由于项目仍然很小,我只是使用了一个工作样本的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
答案 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属性明确封送您的类型。