3

私はC#で書かれたdllを持っていて、COMに公開されています。ビルダーでdllを使用しています...クラスをインスタンス化できますが、C#メソッド呼び出しからの戻り値のマーシャリングに問題があります。

C#

public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
   return "value";
}

ビルダーにインポートされたときの変換された関数:

virtual HRESULT STDMETHODCALLTYPE GetValue(LPWSTR key/*[in]*/, 
                                           BSTR* pRetVal/*[out,retval]*/) = 0;

私はC++についてほとんど知りません。'key'パラメーターは、パラメーターで' MarshalAs'属性を使用できるため、正常に渡されますが、戻り値として宣言する方法がわからないか、呼び出し方がわかりません。 C ++側で機能します(推測するだけで、いくつかのことを試しました)。

更新:さて、私はアントンの例を取り、ハンスのコメントに基づいて修正を試みることによって問題を解決することができました。Antonsの回答は彼が示すとおりに正確に機能しますが、メモリ管理の問題について懸念が表明されたため、C#でreturn属性を適用せず、C++コードは次のように関数を呼び出します。

BSTR result;
obj->GetValue(key, &result);
SysFreeString(key);
SysFreeString(result);

私はこれを手伝ってくれた両方の答えを信用できればいいのにと思います。どちらも私が必要な情報を提供するために必要でした。

4

2 に答える 2

7

[return:]属性を適用できますが、これは本当に悪い考えです。この関数シグネチャの問題は、呼び出し先が文字列にバッファを割り当て、呼び出し元がそれを解放する必要があることです。そのためには、両方が同じヒープを使用する必要があります。これは、LPWSTRの使用を強制した場合には当てはまりません。CLRは独自のヒープを使用し、ネイティブコードからアクセスできず、必要なヒープハンドルを取得できません。

両方のコードで同じヒープを使用する必要があります。そして、特にこの目的のために、COMヒープがあります。BSTRはそのヒープを使用する文字列型であり、CLRは、署名からわかるように自動的にヒープを使用します。これを使用するには、呼び出し後にpRetValポインターにアクセスするだけです。これは、内部のwchar_t*です。そして、後でそれを解放する必要があります。SysFreeString()を呼び出します。

于 2012-11-09T00:58:03.580 に答える
4

戻り値に属性を適用するには:

[return: MarshalAs(UnmanagedType.LPWStr)]
public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
   return "value";
}

(私は思う)を使用して手動で文字列を解放する必要がありますCoTaskMemFree

LPWSTR result ;
if (SUCCEEDED (obj->GetValue (key, &result)))
{
    // use result and free it when no longer needed
    CoTaskMemFree (result) ;
}
于 2012-11-09T00:08:41.913 に答える