6

I have two .NET classes exposed via COM interop - let's say Foo and Bar, and I need to pass an argument of type Foo to a method defined in Bar. Something like this:

[ComVisible(true)]
public class Foo
{
    // whatever
}

[ComVisible(true)]
public class Bar
{
    public void Method(Foo fff)
    {
        // do something with fff
    }
}

When I run the following VBS (using cscript.exe):

set foo = CreateObject("TestCSProject.Foo")
set bar = CreateObject("TestCSProject.Bar")
call bar.Method(foo)

I get an error:

D:\test.vbs(3, 1) Microsoft VBScript runtime error: Invalid procedure call or argument: 'bar.Method'

However, if I change the Method declaration to this:

    public void Method(object o)
    {
        Foo fff = (Foo)o;
        // do something with fff
    }

everything works. I tried some magic with interfaces, attributes, etc. but no luck so far.

Any insight?

Many thanks

2
  • It should work as posted, VBScript uses late binding. Try to improve your snippet to create an example that fails the same way. Commented Jan 25, 2011 at 13:54
  • @Hans - I added the VBS snippet which fails. Everything copy/pasted from real code. Thanks Commented Jan 25, 2011 at 14:19

2 Answers 2

6

Make sure, you define a GUID attribute, this is necessary if you make a QueryInterface (VB does probably). You have to generate a new unique GUID for every comvisible class.

[Guid("77777777-3333-40df-9C0D-2B580E7E1F3B")]
[ComVisible(true)]
public class Foo
{
}

Then i would strongly recommend to write interfaces for your COM objects, and set the ClassInterface to None, so no internals are revealed. Your typelibrary will be much cleaner this way.

[Guid("88888888-ABCD-458c-AB4C-B14AF7283A6B")]
[ComVisible(true)]
public interface IFoo
{
}

[ClassInterface(ClassInterfaceType.None)]
[Guid("77777777-3333-40df-9C0D-2B580E7E1F3B")]
[ComVisible(true)]
public class Foo : IFoo
{
}
Sign up to request clarification or add additional context in comments.

5 Comments

VB doesn't query for the specific interface. It uses IDispatch. Anyway, the problem here was in the way the Foo parameter is marshaled.
@Ran With marshalling it as IUnknown you are doing the same as Elephantik did with declaring the parameter as object, that worked but that's not strong typed. IDispatch directly inherits from IUnknown, so VB can use a QueryInterface when asking for a specific interface (or class).
Actually, I did that. Created interfaces, GUIDed everything, but no luck. I just didn't want to flood the source code.
@Elephantik - That's the way we do it always. Did you set the ClassInterfaceType.None Attribute for the CoClass, so only the interface is exported? The parameter of "Method" should be of type IFoo then of course (not Foo).
I tried ClassInterfaceAttribute and it worked, then I removed it and it still worked. So I recreated the example and out of the blue, everything works. Absloutely no idea what was wrong. Anyway, thanks for help.
3

After struggling with this same issue for a while, I found that is was having issues with passing argments by reference instead of by value. See here:

http://msdn.microsoft.com/en-us/library/ee478101.aspx

So I just added round brackets to the passed argument in VB Script, and it seemed to have solved the problem. So in your example, just doing this:

Set foo = CreateObject("TestCSProject.Foo")
Set bar = CreateObject("TestCSProject.Bar")
Call bar.Method((foo))

Should work as expected, without having to set the ClassInterface attribute, and without using Interfaces.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.