2012-05-04 13 views
0

次のコードは、COMクライアント1台につき、ありがとうございましたが、新しいクライアント(同じソフトウェアの更新版)string_array_to_bstr_safearray_variantがアクセス違反をスローし、すべてが死にます。COM:BSTRのSafeArrayを作成するアクセス違反

誰かが私が前に逃げていた何か間違っていることを教えてもらえますか?メモリを正しく割り当てることができませんか?

#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のコンストラクタ内で失敗しました。

編集:別の最近のステップスルーでループに失敗しました。だから、おそらく問題は@terriblememoryが示唆するようにCComSafeArrayにありますか?

+0

COM、SafeArrays&BSTRs ... Oh my! –

+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ではなくクライアントによって所有されていると言います。それに添付してラッパーを範囲外にすることで、私はセーフアレイの割り当てを解除しました。 return文の前にこれを追加することで修正されました。

1

CComSafeArrayのドキュメントでは、実際にBSTRsをサポートしているとは言えません。基になるSAFEARRAYにBSTRの機能フラグが設定されていますか? (これは本当の答えではありませんが、私はただのコメントにはカルマを持っていません、申し訳ありません)

+0

良い質問。さて、設定されている機能フラグは、 'FADF_BSTR'(すべてうまくいっている)と' FADF_HAVEVARTYPE'です。 2番目のものはわかりませんが、 "fFeaturesフィールドにFADF_HAVEVARTYPEが含まれている場合、cLocksフィールドには配列内の要素の型を指定するVARIANT型定数が上位ワードに含まれていなければなりません。 cLocksフィールドの上位ワードを0に設定しなければならない(MUST) "*' cLocks'は '1'に設定され、その上位ワードはゼロでなければならず、バリアント型は 'VT_EMPTY'ですhttp://msdn.microsoft.com/en -us/library/cc237865%28v = prot.13%29.aspxは間違っている可能性がありますか? –

+0

興味深い。ドキュメントが間違っていると思われます.FADF_HAVEIIDエントリのコピー&ペーストのようです。私はオフセット-4にVARIANTTYPEがあると言っているはずです。いずれにせよ、それは妥当と思われます。 – terriblememory

+0

ハングアップ、out_arrayをout_variantにデタッチする必要はありませんか? CComVariant ccv(out_array.Detach()); – terriblememory

関連する問題