C#からC ++/CLIへのインターフェイスの配列を渡す
質問
私は、C#からC ++/CLIまでのインターフェイスの配列を渡そうとしています。これがコードです:
// *** SafeArrayTesting_PlusPlus.cpp ***
#include "stdafx.h"
#include <comdef.h>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace SafeArrayTesting_PlusPlus {
public ref class MyCppClass
{
public:
MyCppClass();
~MyCppClass();
void SetMyInterfaces(
array<SafeArrayTesting_Sharp::MyInterface^>^ myInterfaces);
};
MyCppClass::MyCppClass(){}
MyCppClass::~MyCppClass(){}
void MyCppClass::SetMyInterfaces(array<SafeArrayTesting_Sharp::MyInterface^>^
myInterfaces)
{
// Create safearray
SAFEARRAY *safeArrayPointer;
SAFEARRAYBOUND arrayDim[1]; // one dimensional array
arrayDim[0].lLbound= 0;
arrayDim[0].cElements= myInterfaces->Length;
safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);
// copy ints to safearray
for (long lo= 0;lo<myInterfaces->Length;lo++)
{
IntPtr myIntPtr = Marshal::GetIUnknkownForObject(myInterfaces[lo]);
SafeArrayPutElement(
safeArrayPointer,
&lo,
static_cast<void*>(myIntPtr)
);
}
// do something with the safearray here - area XX
}}
// *** SafeArrayTesting_Main.cs ***
using SafeArrayTesting_PlusPlus;
using SafeArrayTesting_Sharp;
namespace SafeArrayTesting_Main
{
class SafeArrayTesting_Main
{
static void Main()
{
var myCppClass = new MyCppClass();
MyInterface myInterface = new MyClass();
myCppClass.SetMyInterfaces(new[]{ myInterface });
}
}}
// *** SafeArrayTesting_Sharp.cs ***
using System;
using System.Runtime.InteropServices;
namespace SafeArrayTesting_Sharp
{
[ComVisible(true)]
public interface MyInterface
{
int MyInt { get; set; }
string MyString { get; set; }
DateTime MyDateTime { get; set; }
}
[ComVisible(true)]
public class MyClass : MyInterface
{
public int MyInt{get;set;}
public string MyString{get;set;}
public DateTime MyDateTime{get; set;}
}
// Just to please the compiler; bear with me.
class DummyClass { static void Main() { } }
}
ここに書いたように、コードは実行されてきれいにコンパイルされます。ただし、「エリアxx」部分を実行すると、 System.Runtime.InteropServices.SEHException
.
XXコードは、Safearrayポインターを受け入れる自動生成メソッドを呼び出す単一の行です。この方法の宣言は次のとおりです(.tlhファイルから):
virtual HRESULT __stdcall put_SafeArray (
/*[in]*/ SAFEARRAY * pRetVal ) = 0;
実際、この方法はSafearrayを.NETアレイに変換すると思います。これはすべて、当時会社が運営している変換プロジェクトの一部です。したがって、Safearrayを使用する代わりにはありません。
とにかく、xx部品のないコードがバグがない場合、本当に驚くでしょう。 C ++に関しては、私はかなり初心者です。いくつかの問題を見つけるのを手伝ってくれませんか?誰かがサフェレの妥当性をテストするより良い方法を提案できるなら、それは助けになるでしょう。
(ところで、これは質問のより複雑なバリエーションです SafearrayputelementメソッドSystem.AccessViolationExceptionをスローします 、C#からC ++/CLIにintsの配列を渡していました。)
解決
いくつかの問題。 1つは、実際にアレイにバリアントを保存しません。これは最終的にはどこにも行かず、Safearrayは管理されたオブジェクトへの参照を保存することはできません。ガベージコレクターはオブジェクトを移動し、管理されていないコードが保持している参照を表示できないため、参照を更新できません。
せいぜい、VT_UNKNOUNTまたはVT_DISPATCHの配列を作成できます。ただし、これらの管理されたオブジェクトのcomインターフェイスポインターを取得することはできません。これらは[comvisible]ではありません。それを修正すると、marshal.getidispatchforobject()またはmarshal.getiunknownforobject()を使用して、インターフェイスポインターを取得して配列に保存します。