2012-05-04 51 views
0

下面的代碼一個SAFEARRAY工作就好了謝謝你一個COM客戶端,但隨着新的客戶端(相同的軟件的更新版本)string_array_to_bstr_safearray_variant引發訪問衝突,一切都死了。COM:訪問衝突使得BSTRs

誰能告訴我,如果我這樣做,我與前越來越遠一些錯誤..?我沒有正確地分配內存嗎?

#include "comutil.h" 

void string_array_to_bstr_safearray_variant(long arraylength,char ** in_array,VARIANT *out_variant) 
{ 
    CComSafeArray<BSTR> out_array; 
    ATLENSURE_SUCCEEDED(out_array.Create(arraylength)); 
    for (int i=0;i<arraylength;i++) 
     ATLENSURE_SUCCEEDED(out_array.SetAt(i,_com_util::ConvertStringToBSTR(in_array[i]))); 
    CComVariant ccv(out_array); 
    HRESULT hr = ccv.Detach(out_variant); 
    ATLENSURE_SUCCEEDED(hr); 
} 

//names: output parameter to contain variant holding safearray of bstrs 
STDMETHODIMP CCalculation::get_output_shortnames(VARIANT* names) 
{ 
    char** names_array = calc_get_short_output_names(calc); //this works fine 
    string_array_to_bstr_safearray_variant(output_length,names_array,names); //this fails before returning 
    return S_OK; 
} 

編輯:調試信息

沒有一個調試器,我得到一個訪問衝突。

使用調試程序逐句通過此代碼它似乎工作。 output_length設置正確;據我所知,通過變量觀察,​​被創建並正確填充,out_variant也是如此。但是,COM客戶端仍然失敗,說"lisp value has no coercion to VARIANT with this type: #<safearray...>"(這很奇怪,因爲先前版本的客戶端解釋返回值就好)。然後它崩潰抱怨它已經沒有了記憶。

在調試器內運行代碼,但讓它運行而不是步進,它在CComVariant的構造函數中失敗,抱怨由於對SafeArrayCopy的內部調用失敗而拋出無效參數。

編輯:另一個近期逐步通過它在循環失敗了,所以也許這個問題是CComSafeArray爲@terriblememory建議?

+0

COM,SafeArrays&BSTR ......哦,我的! –

+0

烏雲分割,閃電雷擊,給* output_length *變量一個值。它的邊緣肯定會有點脆。不要編寫返回不返回*數組長度*的數組的函數。他們從根本上是不安全的。矢量<>是一個明顯的選擇。 –

+0

Lol :)是的,'output_length'是一個類成員,並且在get_output_shortnames()被調用的時候有效。 'calc_get_short_output_names'是一個C接口。這不是錯誤。 –

回答

1

嗯終於讓我找到這個問題的答案!問題中發佈的代碼是正確的。之前存在導致未定義行爲的代碼:

STDMETHODIMP CCalculation::configure(VARIANT radii) // radii contains a safearray of doubles 
{ 
CComSafeArray<double> radii_sa; 
radii_sa.Attach(radii.parray); 
ULONG num_radii = radii_sa.GetCount(); 

//unpack radii array into c-style array 
double *radii_array = new double[num_radii]; 
for (long i=0;i<num_radii;i++) 
radii_array[i] = radii_sa.GetAt(i); 

//...do something with radii_array... 

delete[] radii_array; 

return S_OK; 
} 

您是否發現了故意的錯誤? COM規則說半徑是由客戶擁有的,而不是我的dll。通過附加它,然後讓包裝器超出範圍,我正在釋放safearray。通過在返回語句之前添加以下內容進行修復:

radii_sa.Detach(); 
1

CComSafeArray的文檔實際上並沒有說它支持BSTR。 BSTR的功能標誌是否在底層SAFEARRAY中設置? (這是不是一個真正的答案,但我沒有因果報應,只是發表評論,對不起!)

+0

好問題。那麼,設置的功能標誌是'FADF_BSTR'(一切正常)和'FADF_HAVEVARTYPE'。我不確定第二個是什麼,但msdn說*「如果fFeatures字段包含FADF_HAVEVARTYPE,那麼cLocks字段必須在其高位字中包含一個VARIANT類型常量,用於指定數組中元素的類型;否則, cLocks字段的高位字必須設置爲0.「*'cLocks'設置爲'1',因此它的高位字必須爲零,作爲變量類型是'VT_EMPTY' http://msdn.microsoft.com/zh-cn/ -us/library/cc237865%28v = prot.13%29.aspx可能是錯誤的嗎? –

+0

有趣。我懷疑文檔是錯誤的 - 它看起來像FADF_HAVEIID條目的複製和粘貼。我猜想它應該說在offset -4處有一個VARIANTTYPE。無論如何,它確定似乎是合理的。 – terriblememory

+0

等一下,你不需要把out_array分解成out_variant嗎?即CComVariant ccv(out_array.Detach()); – terriblememory