melaos
melaos

Reputation: 8408

how to pass parameters to a function in a .net dll via COM/VB6?

i have a .net dll written in c# which reads data off a data source and acts as a wrapper to allow other apps to call its function to retrieve those data. the thing is i didn't anticipate the .net dll to be used for other than .net apps, so now i was told this all is going to be used in a vba/powerpoint macro which i figure is rather similar to a vb6 app, so that is how i'm planning to test it right now.

after some googling and even posting some question here in so, i manage to get the dll to be referenced inside of vb6, but when i try to call a function which have any parameters, i'll get the error run-time message of error 450 wrong number of arguments or invalid property assignment.

Questions

So what am i doing wrong? and can someone please provide some resources or sample codes that i can learn on how to properly write a .net dll which has functions with parameters that can be called from vb6/vba app?

And if my codes are a bit too messy to read :), then perhaps you guys can help to tell me how to put parameters to work in this sample which i learn from codeproject, its returning the same error message when i include some parameters there.

UPDATES:

i found another set of sample codes here, but unfortunately it only passes parameters as integer, and when i try to do a sample function which passes parameters as string, i get the same error. Am i missing something fundamentals here? anybody care to flame a noobie?

Updates 2:

Just in case there's anybody else who stumbled onto this problem, i didn't really found out why or what was causing the problem but since the project was still rather small, i just use a working sample for the dll which was able to return string properly and start moving function per function over to it, and it's working fine now :)

thanks!!!

the .net dll codes are as follows:

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)
        {
        ...
        }
}

and this is how i'm calling it from 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

Upvotes: 3

Views: 3801

Answers (4)

C-Pound Guru
C-Pound Guru

Reputation: 16348

I noticed you're missing [ComVisible(true)].

Interface header should look like:

[Guid("CF4CDE18-8EBD-4e6a-94B4-6D5BC0D7F5DE")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IFoo {

    [DispId(1)]
    string MyMethod(string value);
}

Class header should look like:

[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;
    }
}

Upvotes: 2

Andreas F
Andreas F

Reputation: 404

Have you tried looking at the type library (using OleView.exe) after you exported/registered the assembly?

My suspicion is that all your methods return strings, whereas COM methods tend to return HRESULT's (no idea if this is generally true - actually your example codeproject page seems to suggest otherwise), which means you would need to put your input and output into the method arguments and explicitly marshal them with [in], [out], and/or [retval].

Anyways, take a look at the type library and check if it looks like you expect it to look. If not you may have to explicitly marshal your types using the MarshalAs attribute.

Upvotes: 1

Eric Nicholson
Eric Nicholson

Reputation: 4123

I believe DispID(1) is reserved for ToString or something like that (it's been a while) Try starting your DispIDs at 2.

Upvotes: 1

AnthonyWJones
AnthonyWJones

Reputation: 189437

Try changing this chunk of code:-

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

to

[InterfaceType(ComInterfaceType.InterfaceIsDual)]

I'm not sure why you get the error you are however early (or VTable) binding is what you VB6 code appears to be attempting but InterfaceIsIDispatch doesn't support that. Its possible VB6 itself is falling back to late binding but why would you want it to?

Also drop all the DispId attributes they are only needed if you really need to emulate an existing COM interface.

Upvotes: 1

Related Questions