2010-06-07 28 views
2

我試圖公開一個相當簡單的C#類到COM應該可以從VBScript(等)使用。 有些對象需要通過COM調用創建,稍後將用於進一步調用。暴露的類和接口的定義是這樣的:將參數從VBScript傳遞到C#中實現的COM接口的正確方法是什麼?

namespace Test 
{ 
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface IComInterface 
    { 
     IFoo CreateFoo(); 
     void UseFoo(int x, IFoo f); 
    } 

    [ClassInterface(ClassInterfaceType.None)] 
    public sealed class CComInterface : IComInterface 
    { 
     public CComInterface() {} 
     public IFoo CreateFoo() { return new Foo(); } 
     public void UseFoo(int x, IFoo f) { f.Bar(); } 
    } 

    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface IFoo 
    { 
     void Bar(); 
    } 

    [ClassInterface(ClassInterfaceType.None)] 
    public class Foo : IFoo 
    { 
     internal Foo() {} 
     public void Bar() {} 
    } 
} 

VBScript中最簡單的能想到的COM客戶端不會這樣:

Dim ci 
Set ci = WScript.CreateObject("Test.CComInterface") 
Dim foo 
Set foo = ci.CreateFoo 
foo.Bar 
ci.UseFoo 0, foo 

雖然呼叫酒吧成功,調用UseFoo失敗「錯誤5 :無效的過程調用或參數無效」

生成的IDL似乎沒對我說:

dispinterface IComInterface { 
    properties: 
    methods: 
     [id(0x60020003)] 
     IFoo* CreateFoo(); 
     [id(0x60020004)] 
     void UseFoo(
         [in] long x, 
         [in] IFoo* f); 
}; 

VBS的調用成功,當我換的第二個參數在這樣的括號:

ci.UseFoo 0, (foo) 

據我瞭解(我不是專家的VBScript但是)這會強制引用到foo按值傳遞,即正在製作參考文獻的副本。

如何更改界面以便可以直接使用foo參考調用界面?因爲這將是客戶使用的公共接口,所以我不喜歡解釋爲什麼所有創建的對象需要傳回額外的一對括號中的想法...

+0

我看不出有[進程id]在這個片段。這與真實代碼有多接近? CreateFoo()實際上是否返回不同的接口? – 2010-06-07 16:58:47

+0

這是我用來從一個更大的項目中重現問題的真實代碼。它沒有顯式的ProgId,它是從命名空間和類名生成的。 – nopopem 2010-06-08 08:29:26

回答

2

Louis.fr在MSDN社會幫了我 - 關鍵是要告訴編組如何封送參數是這樣的:

public void UseFoo(int x, [MarshalAs(UnmanagedType.IDispatch)] IFoo f) { f.Bar(); } 
1

嘗試將C#接口更改爲採取ref參數。

+0

已經嘗試過,結果是tlb列出參數爲 void UseFoo([in] long x,[in,out] IFoo ** f); 但我仍然需要將它包裝在VBScript中的括號內。 – nopopem 2010-06-08 08:40:30

相關問題