PInvoke を使用して、C++ ライブラリ (libclang) を C# ラッパーにラップしようとしています。
構造体を返す C++ メソッドを呼び出そうとするまでは、すべてがピカピカでした。すべて本通りにやったのですが、このメソッドが呼び出されると AccessViolationException が発生します。
今読んだところ、オブジェクトの記憶イメージに何か問題があるためだろうと読みました。すべてのアーティビュートを配置したかどうか、どこにもないものをチェックして再チェックしましたが、例外は消えません。(私はこのコードを何時間も見てきたので、いくつか見落としているかもしれませんが、皆さんはそうではありません)。
C++ の部分 (私のコードではありませんが、動作することは確かです):
CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
/* Parse the hell out of a lot of data, an then make a string
In the end, string gets wrapped in a custom struct: CXString.
*/
return createCXString(Out.str(), true);
}
CXString は次のとおりです。
typedef struct {
void *data;
unsigned private_flags;
} CXString;
したがって、ラップされた C++ のオリジナルを表す C# クラスがあります。
public class Diagnostic
{
private IntPtr _nativeObject;
internal IntPtr NativeObject { get { return _nativeObject; } }
[DllImport("libclang.dll", EntryPoint = "clang_formatDiagnostic")]
[return: MarshalAs(UnmanagedType.LPStruct)]
private static extern CXString FormatDiagnostic(IntPtr diag, uint options);
public Diagnostic(IntPtr native)
{
_nativeObject = native;
}
public string GetString(DiagnosticDisplayOptions options = DiagnosticDisplayOptions.DisplaySourceLocation)
{
var cxstr = FormatDiagnostic(_nativeObject, (uint)options); //<-- I get the exception here
return cxstr.GetString();
}
}
必要な関数も C テイスト (グローバル) で実装されているため、私の C# クラスでは OO の印象を与えることができますが、実際には C++ オブジェクトの IntPtr 表現を格納しています ( _nativeObject
)。したがって、に格納されているオブジェクト_nativeObject
は実際には CXDiagnostic であると確信しています (同じライブラリの別の関数から参照が返されました)。
FormatDiagnostic メソッドで使用しようとしている実際のオブジェクトは、別のラッパー クラス (TranslationUnit) のコンストラクターから初期化されます。
public TranslationUnit(/*lots of params to init the unit*/)
{
//... there are some int conversions and initialization failsafe codes here
//this is a property of TranslationUnit
Diagnostics = new List<Diagnostic>();
//GetDiagnosticsCount is also PInvoke to count CXDiagnostic objects related to the TranslationUnit
var dgCnt = (int)GetDiagnosticsCount(_nativeObject);
for (int i = 0; i < dgCnt; i++)
{
//GetDiagnostic is also PInvoke, gets the CXDiagnostic at the given index
var diag_ptr = GetDiagnostic(_nativeObject, (uint)i);
Diagnostics.Add(new Diagnostic(diag_ptr));
}
//up until now, all the calls seem to work
//I get the expected count of diagnostics and none of the other
//PInvoke calls throw exceptions. They use IntPtrs, but none of them
//use structs.
}
したがって、MSDN チュートリアルが示唆するように、CXString 構造体をマーシャリングする C# クラスを作成しました。これは次のようになります。
[StructLayout(LayoutKind.Sequential)]
public class CXString
{
public IntPtr data;
public uint private_flags;
}
コードが呼び出しに到達すると、AccessViolationException が発生しFormatDiagnostic
ます。うまくいかなかった可能性のあるヒントはありますか?
編集:
CXDiagnostic は、元の C++ コードのポインター型です。
typedef void *CXDiagnostic;