как да предам параметри на функция в .net dll чрез COM/VB6?

имам .net dll, написан на c#, който чете данни от източник на данни и действа като обвивка, за да позволи на други приложения да извикат неговата функция, за да извлекат тези данни. работата е там, че не очаквах .net dll да се използва за приложения, различни от .net, така че сега ми беше казано, че всичко това ще се използва в макрос vba/powerpoint, който според мен е доста подобен на приложение vb6 , така че планирам да го тествам точно сега.

след малко гугъл и дори публикуване на някакъв въпрос тук, успях да накарам dll да бъде препратен вътре във vb6, но когато се опитам да извикам функция, която има някакви параметри, ще получа съобщение за грешка по време на изпълнение 450 грешен брой аргументи или невалидно присвояване на свойства.

Въпроси

И така, какво правя грешно? и може ли някой да предостави някои ресурси или примерни кодове, които мога да науча как правилно да пиша .net dll, който има функции с параметри, които могат да бъдат извикани от приложението vb6/vba?

И ако моите кодове са твърде объркани за четене :), тогава може би вие можете да ми помогнете да ми кажете как да поставя параметрите да работят в този пример, който научавам от codeproject, връща същото съобщение за грешка, когато включа някои параметри там.

АКТУАЛИЗАЦИИ:

тук намерих друг набор от примерни кодове, но за съжаление той минава само параметри като цяло число и когато се опитам да направя примерна функция, която предава параметри като низ, получавам същата грешка. Пропускам ли нещо основно тук? някой иска да запали 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

person melaos    schedule 17.08.2009    source източник


Отговори (4)


Забелязах, че ти липсва [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;
    }
}
person C-Pound Guru    schedule 19.08.2009

Опитайте да промените тази част от кода: -

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

to

[InterfaceType(ComInterfaceType.InterfaceIsDual)]

Не съм сигурен защо получавате грешката, но рано (или VTable) свързването е това, което вашият VB6 код изглежда се опитва, но InterfaceIsIDispatch не поддържа това. Неговият възможен VB6 се връща към късно свързване, но защо бихте го искали?

Също така премахнете всички атрибути на DispId, те са необходими само ако наистина трябва да емулирате съществуващ COM интерфейс.

person AnthonyWJones    schedule 17.08.2009
comment
@Anthony, благодаря, вече не получавам съобщение за грешка, но все още не получавам данни от функциите :( - person melaos; 18.08.2009
comment
@Melaos: Поне това е напредък ;). Сега бих предложил да компилирате вашето VB6 приложение, да го стартирате и да прикачите VS дебъгера към него. Уверете се, че кодът във вашата .NET dll прави това, което мислите, че прави, и получава параметрите, които смятате, че е. - person AnthonyWJones; 18.08.2009
comment
@Anythony, да, радвам се, че поне мога да заобиколя частта с грешката и всъщност се опитвам да науча как да отстранявам грешки в цялото това нещо сега, тъй като използвам vs.net express, не мога да го направя методът за отстраняване на грешки при прикачване :( - person melaos; 18.08.2009
comment
Тествали ли сте .NET самостоятелно във VS Express? Можете ли да създадете VB6 макет за вашия .NET компонент и да тествате своя VB6 код с него? - person AnthonyWJones; 18.08.2009
comment
@Anthony, създадох друго c# приложение, за да тествам dll, тъй като не разбрах, че dll ще бъде препращано от com приложение :(, и предлагате ли ми да създам dll във vb6? - person melaos; 19.08.2009
comment
Не, просто ви предлагам да тествате .NET страната и страната VB6 отделно, преди да опитате да ги обедините. Трябва да се съмнявам, че самият Interop по някаква причина не успява да върне стойност, по-вероятно е .NET компонентът просто да не прави това, което очаквате, когато е извикан от VB6. Честно казано, този вид работа е много трудна, ако нямате правилните инструменти. - person AnthonyWJones; 19.08.2009

Вярвам, че DispID(1) е запазен за ToString или нещо подобно (мина известно време) Опитайте да започнете своите DispID от 2.

person Eric Nicholson    schedule 17.08.2009
comment
Това не е вярно, единствените запазени DispID са 0 и по-ниски, например -4 се използва за получаване на IEnumVariant, който поддържа For Every. - person AnthonyWJones; 18.08.2009
comment
Грешка, изглежда, че ToString всъщност е 0 на _Object. Благодаря! - person Eric Nicholson; 18.08.2009

Опитахте ли да разгледате библиотеката с типове (с помощта на OleView.exe), след като сте експортирали/регистрирали асемблирането?

Моето подозрение е, че всичките ви методи връщат низове, докато COM методите са склонни да връщат HRESULT (нямам представа дали това като цяло е вярно - всъщност вашата примерна страница с кодов проект изглежда предполага друго), което означава, че ще трябва да поставите входа и изхода си в аргументи на метода и изрично ги маршалирайте с [in], [out] и/или [retval].

Както и да е, погледнете библиотеката с типове и проверете дали изглежда така, както очаквате да изглежда. Ако не, може да се наложи изрично да маршалите вашите типове с помощта на атрибута MarshalAs.

person Andreas F    schedule 17.08.2009