質問
void** を受け取る関数を含む古い C ライブラリがあります。
oldFunction(void** pStuff);
マネージド C++ からこの関数を呼び出そうとしています (m_pStuff は void* 型の親 ref クラスのメンバーです)。
oldFunction( static_cast<sqlite3**>( &m_pStuff ) );
これにより、Visual Studio から次のエラーが表示されます。
エラー C2440:'static_cast' :「cli::interior_ptr」から「void **」に変換できません
コンパイラが私の背後で void* メンバー ポインタを cli::interior_ptr に変換しているのだと思います。
これを行う方法についてアドバイスはありますか?
解決
編集:修正された答え、以下を参照してください。
実際には、oldFunction が pStuff で何を行うのかを知る必要があります。pStuff がアンマネージ データへのポインタである場合は、m_pStuff の定義を次のようにラップしてみてください。
#pragma unmanaged
void* m_pStuff
#pragma managed
これにより、ポインターがアンマネージドになり、アンマネージ関数に渡すことができるようになります。もちろん、管理対象オブジェクトをこのポインターに直接割り当てることはできません。
基本的に、アンマネージ ポインターとマネージ ポインターは同じではなく、基になるデータをコピーする何らかの接着コードがなければ変換できません。基本的にマネージド ポインタはマネージド ヒープを指しますが、これはガベージ コレクションされるため、マネージド ポインタが指す実際のメモリ アドレスは時間の経過とともに変化する可能性があります。アンマネージ ポインターは、ユーザーが明示的に変更しない限り、メモリ アドレスを変更しません。
ただし、クラス定義内でアンマネージド/マネージドを定義することはできません。しかし、このテストコードは問題なく動作しているようです。
// TestSol.cpp : main project file.
#include "stdafx.h"
using namespace System;
#pragma unmanaged
void oldFunction(void** pStuff)
{
return;
}
#pragma managed
ref class Test
{
public:
void* m_test;
};
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
Test^ test = gcnew Test();
void* pStuff = test->m_test;
oldFunction(&pStuff);
test->m_test = pStuff;
return 0;
}
ここでは、まず管理オブジェクトからポインターをコピーし、それを oldFunction に渡します。次に、結果 (おそらく oldFunction によって更新されたもの) を管理オブジェクトにコピーして戻します。マネージド オブジェクトはマネージド ヒープ上にあるため、ガベージ コレクターの実行時にオブジェクトが移動する可能性があるため、コンパイラではそのオブジェクトに含まれるポインターへの参照を渡すことができません。
他のヒント
アドバイスありがとうございます。ポインタは C スタイルの抽象構造を指しています。この構造をマネージド コードに公開したままにすると、定義された構造が欠如しているためにさらに問題が発生すると思います。したがって、C ライブラリを C++ でラップし、次に C++ ラッパーをマネージド C++ でラップすることを考えています。これにより、これらの C 構造がマネージド コードに公開されるのを防ぐことができます。