2012-02-21 59 views
2

我花了最後一天搜索文檔,查看論壇帖子和使用Google搜索來嘗試做一些我猜測可以輕鬆完成的正確信息。異常將VARIANT中的SAFEARRAY傳遞給C#從C++ COM服務器

我有一個非常大的現有C++應用程序,它有一個已經定義的COM服務器,並且有許多暴露的方法。我想在C#應用程序中使用這些COM方法(我在C++中經驗豐富,但是C#新手)。

因此,在我的VS2010 C#應用程序中,我添加了COM服務器作爲參考。 COM方法在對象瀏覽器中可見,並且傳遞單值字符串,浮點數和整數似乎工作正常。

但我很難將試圖讀取從C++ COM服務器傳遞到C#應用程序的SAFEARRAY值。最終,我需要將字符串數組從C++服務器傳遞到C#應用程序,但是在傳遞一組浮點數的過程中,我有構建的代碼,但是當我嘗試轉換包含浮點數組的System.Object時發生以下異常to(float []),

「異常{System.InvalidCastException:無法強制類型'System.Object []'的對象鍵入'System.Single []'。」

通過intellisence,我可以看到對象包含正確的8760長浮點數組,但我無法訪問C#中的數據。

這裏是C#端的代碼(d2RuleSet是在DOE2Com COM服務器中定義的接口)。上面的例外引發到下面的最後一行。

DOE2ComLib.DOE2Com d2RuleSet; 

d2RuleSet = new DOE2ComLib.DOE2Com(); 

System.Int32 i_Series =0; 

System.Object pv_WeatherData; 
float[] faWeatherData; 

iOut = d2RuleSet.GetWeatherData(i_Series, out pv_WeatherData); 
Type typeTest; 
typeTest = pv_WeatherData.GetType(); 
int iArrayRank = typeTest.GetArrayRank(); 
Type typeElement = typeTest.GetElementType();      
faWeatherData = (float[])pv_WeatherData; 

下面是在IDL文件中定義的C++ COM方法

HRESULT GetWeatherData([in] int iSeries, [out] VARIANT* pvWeatherData, [out,retval]  int * piErrorCode); 

下面是其中VARIANT數據被加載C++代碼部分。

void CDOE2BaseClass::GetWeatherData(int iSeries, VARIANT* pvWeatherData, int* piErrorCode) 
{ 
    *piErrorCode = 0; 

    if (iSeries < 0 || iSeries >= D2CWS_NumSeries) 
     *piErrorCode = 1; 
    else if (m_faWeatherData[iSeries] == NULL) 
     *piErrorCode = 3; 
    else 
    { 
     SAFEARRAYBOUND rgsaBound; 
     rgsaBound.lLbound = 0; 
     rgsaBound.cElements = 8760; 

     // First lets create the SafeArrays (populated with VARIANTS to ensure compatibility with VB and Java) 
     SAFEARRAY* pSAData = SafeArrayCreate(VT_VARIANT, 1, &rgsaBound); 
     if(pSAData == NULL) { 
#ifndef _DOE2LIB 
      _com_issue_error(E_OUTOFMEMORY); 
#else 
//RW_TO_DO - Throw custom Lib-version exception 
      OurThrowDOE2LibException(-1,__FILE__,__LINE__,0,"OUT OF MEMORY"); 
#endif //_DOE2LIB 
     } 

     for (long hr=0; hr<8760; hr++) 
     { 
      COleVariant vHrResult(m_faWeatherData[iSeries][hr]); 
      SafeArrayPutElement(pSAData, &hr, vHrResult); 
     } 

     // Now that we have populated the SAFEARRAY, assign it to the VARIANT pointer that we are returning to the client. 
     V_VT(pvWeatherData) = VT_ARRAY | VT_VARIANT; 
     V_ARRAY(pvWeatherData) = pSAData; 
    } 
} 

預先感謝此問題的幫助,我覺得我花了什麼應該是一個簡單的問題太多時間。也請張貼任何涵蓋本地C++和C#之間互操作的鏈接或書籍(我認爲我已經通過大部分Visual Studio/MSDN文檔進行了ping操作,但也許我錯過了某些內容)。

-----------------原問題結束------------------------- ----------------------------- 我正在編輯發佈phoog下面成功解決方案的代碼,以便其他人可以閱讀和使用它。

int iOut = 0; 
System.Int32 i_Series =0; 
System.Object pv_WeatherData = null; 

iOut = d2RuleSet.GetWeatherData(i_Series, out pv_WeatherData); 
Type typeTest; 
typeTest = pv_WeatherData.GetType(); 
int iArrayRank = typeTest.GetArrayRank(); 
Type typeElement = typeTest.GetElementType(); 

//float[] faWeatherData = (float[])pv_WeatherData; 
float[] faWeatherData = ConvertTheArray((object[])pv_WeatherData); 

....

float[] ConvertTheArray(object[] inputArray) 
{ 
    float[] result = new float[inputArray.Length]; 
    for (var index = 0; index < result.Length; index++) 
     result[index] = (float)inputArray[index]; 
    return result; 
} 
+0

您確定'pv_WeatherData'中的數據是IEEE單浮點數而不是雙倍嗎?如果將它轉換爲Object []或Array,並在調試器中檢查它,會發生什麼?哦,我只是注意到它確實是一個InvalidCastException。你有錯誤的類型,需要投射。 – codekaizen 2012-02-21 23:23:31

+0

在另一種情況下會發生什麼?例如如果我有一個C++函數在我的C#應用​​程序中使用,並且函數期望收到一個矩陣,例如:MyUnmanagedFunction(&Array);我如何傳遞數組? – willyMon 2014-11-28 04:10:53

回答

1

編組SAFEARRAY是System.Object[];你不能參考 - 將其轉換爲System.Single[]。您必須投射各個元素。這會工作,假設參數數組中的所有元素其實都是盒裝花車:

float[] ConvertTheArray(object[] inputArray) 
{ 
    float[] result = new float[inputArray.Length]; 
    for (var index = 0; index < result.Length; index++) 
     result[index] = (float)inputArray[index]; 
    return result; 
} 

你可以做到這一點與使用LINQ少了很多打字,但你是一個C#新手我想到了一個更基本解決方案可能會更好。

編輯

既然你在你的評論,你object[]作爲一個object引用表明,這裏的用法例如:使用

object obj = GetMarshalledArray(); 
float[] floats = ConvertTheArray((object[])obj); 

EDIT 2

較短的解決方案Linq:

float[] ConvertTheArray(object[] inputArray) 
{ 
    return inputArray.Cast<float>().ToArray(); 
} 
+0

phoog,非常感謝您的快速回復。問題是pv_WeatherData是單個對象而不是對象數組,所以當我嘗試將它傳遞給ConvertTheArray時,出現編譯錯誤。 pv_WeatherData對象具有System.Array類型,當我將光標懸停在其上時,智能感知顯示浮點數。我沒有做任何自定義編組,只是在我的C#應用​​程序中引用了COM服務器的類型庫。 – TommyVee 2012-02-21 23:31:33

+0

,我對pv_WeatherData代表的類型感到困惑。我上面粘貼的異常說「System.InvalidCastException:無法強制類型'System.Object []'強制類型'System.Single []'」的對象,但是pv_WeatherData的聲明是System.Object。但是,當我在調試器中將pv_WeatherData懸停在異常之前時,pv_WeatherData的類型是object []。 – TommyVee 2012-02-21 23:42:12

+0

@TommyVee如果對象引用指向'System.Object []'類型的對象,就像異常消息所暗示的那樣,那麼你可以將它轉換爲'(object [])obj'。 – phoog 2012-02-21 23:44:50

相關問題