2011-01-05 40 views
0

我有(在C#)COM組件C#字符串數組,具有以下接口:通行證結構或從C++使用COM

namespace InterOp 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    public struct MyStruct 
    { 
     [MarshalAs(UnmanagedType.BStr)] 
     public string name; 
     [MarshalAs(UnmanagedType.BStr)] 
     public string surname; 
     public int age; 
    } 

    public interface ITest 
    {   
     void SetStringArray(string[] array); 
     void SetStructArray(MyStruct[] array); 
    } 

    public class Test : ITest 
    { 
     // string arrays 
     public void SetStringArray(string[] array) 
     { 
      for(int i = 0; i < array.Length; i++) 
       MessageBox.Show(array[i]); // just do something with the array values 
     } 

     // struct arrays 
     public void SetStructArray(MyStruct[] array) 
     { 
      for (int i = 0; i < array.Length; i++) 
       MessageBox.Show(array[i].name + ", " + array[i].surname + " (" + array[i].age.ToString() + ")");// just do something with the array values 
     } 
    } 
} 

現在我想從C++數據傳遞給COM對象。 我初始化這樣的接口:

HRESULT hr = CoInitialize(NULL); 
ITest* pTest = NULL; 
hr = CoCreateInstance(__uuidof(Test), NULL, CLSCTX_INPROC_SERVER, __uuidof(ITest), (void**)&pTest); 

但我不能一提到我的數組傳遞給方法,因爲它需要一個SAFEARRAY *數組。我能夠與固定大小的元素,如雙,INT,字符數組陣列創建SAFEARRAYS,它使用類似這工作得很好:

SAFEARRAY* data = SafeArrayCreate(VT_R8, 1, &bound); //8-Byte-Real, 1 dimension 

當然,對於我的用戶自定義的結構沒有「VT_something 「,所以我不知道如何創建SAFEARRAY來解決這個問題。我嘗試過VT_DISPATCH和VT_BSTR,但沒有成功。

傳遞數據的實際方法是這樣的一個:

bool SetStructArrayEx(MyInterOp::MyStruct* array, int arraySize, ITest* comObjectInterface) 
{ 
    bool retVal = false; 

    // Create the safearray environment 
    SAFEARRAYBOUND bound; 
    bound.lLbound = 0; 
    bound.cElements = arraySize; 

    // Init the safearray 
    SAFEARRAY* data = SafeArrayCreate(VT_DISPATCH, 1, &bound); 

    // access the safearray data and copy the original data to it 
    MyInterOp::MyStruct HUGEP* temp; 
    HRESULT hr = SafeArrayAccessData(data, (void HUGEP* FAR*)&temp); 
    if(SUCCEEDED(hr)) 
    { 
     // finally copy the data 
     for(int i=0; i<arraySize; ++i) 
      *temp++ = array[i]; 

     comObjectInterface->SetStructArray(data); 
     SafeArrayUnaccessData(data); 

     retVal = true; 
    } 

    SafeArrayDestroy(data); 

    return retVal; 
} 

...這不工作(主叫SetStructArray異常時Kernel32.dll中)。

任何想法,我錯了嗎?或者什麼工作?

感謝, 馬庫斯

回答

1

它看起來像你的問題是一樣的:https://stackoverflow.com/questions/268117/safearray-of-structs

具體見http://vcfaq.mvps.org/com/4.htm

  • 導入結構到通過從生成的類型庫C++ C#
  • 致電SafeArrayCreateEx(VT_RECORD),SafeArrayAccessDataSafeArrayUnaccessData填充陣列
+0

看起來很有希望。不幸的是,我從一個問題到下一個問題:使用SafeArrayCreateEx()我需要使用GetRecordInfoFromGuids()來獲取IRecordingInfo。爲此,我需要一些我沒有的IDL文件。似乎通常.tlb是從IDL文件創建的,但VS2005 C#編譯器創建了沒有IDL文件的tlb文件...我會繼續嘗試... – 2011-01-06 17:52:02

+0

@Markus您需要什麼IDL - - GUID?啓動OleView(打開Visual Studio命令提示符並鍵入'oleview'),然後將.tlb加載到它。 – 2011-01-06 17:57:33

+0

謝謝 - 我從註冊表中提取了GUID,但使用該工具當然要容易得多。我有問題得到IRecordInfo(實際上它接受我的GUID),但我終於設法解決所有這些 - 它工作正常。您發佈的鏈接非常有幫助! – 2011-01-07 00:23:53

1

COM對結構的支持很差。至少需要使用IRecordInfo來發現結構的佈局,SafeArrayCreateEx()的第四個參數。實際上並不確定CLR是否支持這一點。或者你如何獲得IRecordInfo接口指針。

您的C++代碼否則有正確的想法。不要使用結構,請使用[ComVisible]類。結構成員可以只是屬性。

+0

謝謝,漢斯。獲取IRecordInfo並不像我想的那麼容易,但它終於奏效了,所以我現在可以使用SafeArrayCreateEx並最終傳輸我的數據。 – 2011-01-07 00:25:25