簡體   English   中英

如何將字節數組作為UDT屬性從VB6 / VBA傳遞到C#COM DLL?

[英]How to Pass Byte Arrays as UDT Properties from VB6/VBA to C# COM DLL?

我有一個C#庫,試圖將其公開給VBA。 我可以很好地將參數傳遞給函數(即“ ref byte [] someArray”),但是傳遞對象或結構將不起作用。

如果我嘗試將字節數組作為類的屬性傳遞,則會在VB-中收到以下錯誤

函數或接口標記為受限,或者函數使用Visual Basic不支持的自動化類型

如果我嘗試將字節數組作為結構的屬性傳遞,則會在VB-中收到以下錯誤

我已經為此奮斗了兩天,盡管我不斷找到聲稱有答案的帖子,但沒有一個對我有用。

所以這是我目前的代碼:

[ComVisible(true)]
[Guid("7F53F7A5-15C9-4A99-A855-38F5E87702D0")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]       // Tried as InterfaceIsDual and as InterfaceIsIDispatch
public interface IDetail
{
    [DispId(1)]     // Tried with and without these
    int SomeInt { get; set; }

    [DispId(2)]
    string SomeString { get; set; }

    [DispId(3)]
    byte[] SomeByteArray { 
        return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
        get;
        [param: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
        set; 
    }
}

[ComVisible(true)]
[Guid("F77FB3D4-27E0-4BFA-A21E-5ACB671151E9")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("G4COMTest.Detail")]
public class Detail:IDetail
{
    public int SomeInt { get;set; }
    public string SomeString { get; set; }

    // Tried MarshalAs in all combinations of class and interface
    public byte[] SomeByteArray {
        [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
        get; 
        [param: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
        set;
    }
}

[ComVisible(true)]
[Guid("5E8F9FF0-3156-479E-A91D-0DADD43881FB")]
[ClassInterface(ClassInterfaceType.None)]
public class Worker:IWorker
{
    // works with the 'ref'
    public int ReturnIntWByteArrayParam(ref byte[] testByteArray)
    {
        return testByteArray.Count();
    }

    public int ReturnIntWObjParam(IDetail detail)
    {
        return detail.SomeInt;
    }

    public IDetail ReturnObjNoParams()
    {
        var o = new Detail();
        o.SomeInt = 87;
        o.SomeString = "What are you doing Dave";
        return o;
    }
}

[ComVisible(true)]
[Guid("04962F29-DBBD-48AC-B4FB-180EEF562771")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IWorker
{
    int ReturnIntWByteArrayParam(ref byte[] testByteArray);
    int ReturnIntWObjParam(IDetail detail);
    IDetail ReturnObjNoParams();
}

從VB6調用:

Dim o As New G4COMTest.Worker
Dim d As New G4COMTest.Detail
Dim byt(2) As Byte

d.SomeInt = 356                     '// Works
d.SomeString = "Hello from client"  '// Works
d.SomeByteArray = byt               '// Errors as either class or struct
MsgBox mWorker.ReturnIntWObjParam(d)

在此先感謝您的幫助!

C#數組屬性完全按照您的期望向COM公開了一個getter和setter( MarshalAs屬性是不必要的,封送拆封器默認情況下會正確檢測到它)。

問題在於,設置器與.NET中的所有屬性設置器一樣,按值傳遞value參數。 不幸的是,VBA不支持按值傳遞數組。 從第一天開始,這就是對這種語言的基本限制。 更不幸的是,COM互操作無法提供任何方法來使用屬性覆蓋此行為。 您有兩種選擇:

A-定義您自己的設置器方法,然后從VBA而不是屬性設置器中調用它,例如

void SetSomeByteArray(ref byte[] value) { SomeByteArray = value; }

B-將屬性類型更改為object並使用變量數組而不是強類型數組。

PS:還要注意string屬性。 這些通常可以正常工作,但是如果將null字符串值傳遞給VBA,則會出錯,因為VBA String類型不能存儲null引用。

在您的代碼類中,Detail的ClassInterfaceType設置為None,如果將其設置為AutoDispatch,則您可以運行的代碼。 從MSDN:

對於腳本客戶端,Microsoft Visual Basic 6.0客戶端或任何不緩存接口成員的DispId的后期綁定客戶端,使用類接口是可接受的選項。”

http://msdn.microsoft.com/zh-CN/library/4fcadw4a(v=vs.110).aspx

由於您從中呼叫的客戶端是VB6-您可以將ClassInterfaceType設置為AutoDispatch或什至忽略它(默認為AutoDispatch)。 這將僅生成“僅分發”類接口,並且不包括該接口中的任何成員。 從VB6調用時,直接使用屬性分配數組應該起作用,因為它使用IDispatch Invoke函數(后期綁定)。

我們使用字符串數組對此進行了測試,並且可以正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM