5

ハンス・パッサンが 望むようにこれが私のシナリオです。私は、パフォーマンスを尊重しながらネイティブ コードがすべてのハードワークを実行し、マネージ コードが GUI のみを担当する混合モード アプリケーションを使用しています。また、ユーザーは独自の C# コードを作成して参加します。ネイティブ クラスには C++、GUI とユーザー コードには C#、その間にラッパー クラスには C++/Cli があります。私のすべての C++ クラスの中には、計算の %90 を実行し、毎回異なるパラメーターが作成されるクラスがあります。それを NativeClass と呼びましょう。約あります。この NativeClass のインスタンスは 2000 個あり、計算を行う前に、いくつかのパラメーターに関連する適切なインスタンスを見つける必要があります。そこで、この目的のために、パラメーターがハッシュ コードである hash_map を考案しました。パラメータを取得したら、hash_map で適切なインスタンスを探し、それを見つけて、そのメソッドのいくつかを呼び出します。
ユーザーが C# コードを記述して計算に貢献すると、このクラスはコールバックによってこれらのコードを実行します。これは些細なことですが、ユーザーが作成した .Net クラスに関する情報が必要になることがあります。したがって、その特定の ManagedClass を NativeClass に何らかの方法でアタッチする必要があります。私の最初の解決策は、GChandle.Alloc() を使用してハンドル アドレスを転送することです。しかし、GC が適切に機能しないという懸念もあります。Hans は、Marshal.AllocCoTaskMem() と Marshal.StructureToPtr() を使用してアンマネージド メモリにマネージド オブジェクトを割り当てることを推奨しましたが、これは値型のクラスまたは構造体に有効であると私は信じています。refクラスはどうですか?GC が収集されるのを防ぎながら、NativeClass への参照を渡し、同時に GC を適切に機能させるにはどうすればよいですか?

サンプルコードは次のとおりです。

class NativeClass
{
private:
    int AddressOfManagedHandle;
public:
    static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
    {
// return NativeClass associated with SomeParameter from NativeClassHashMap;
    }
    NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
    {

    }
    int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){ 
// CALCULATIONS
}
};


public ref class ManagedClass : MarshalByRefObject
{
private:
    NativeClass* _nc;
//GCHandle handle;
    void FreeManagedClass()
    {
        Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
        delete _nc;
    }
public: 
    ManagedClass()
    {
        IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
        Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
        _nc = new NativeClass(addr.ToInt32());
    }
    ~ManagedClass() {FreeManagedClass();}
    !ManagedClass() {FreeManagedClass();}
    int GetAddress() {return _nc->GetAddress();};
    static ManagedClass^ GetManagedClass(int SomeParameter)
    {
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid );
    return dynamic_cast<ManagedClass^>(obj);

    }
};

長くなりすぎて、まだわかりにくくてすみません。

4

3 に答える 3

3

私は同様の問題と戦うのにかなりの時間を費やしました.これは私のために働いた解決策の概要です....

  1. マネージ クラスへのハンドルをvoid *
  2. アンマネージド クラスへのポインターをマネージド クラスに格納します (既に行ったように)。
  3. 次のようなものではなく、プレーンな古いものnewを使用してくださいdeleteAllocHGlobal
  4. GCHandlevoid * と管理対象オブジェクト参照の間の変換
  5. 派生元について心配するMarshalByRefObject必要はありません。独自のマーシャリングを行っているため、必要ありません。
  6. マネージ クラスを解放するときは、防御コーディングを覚えておいてください

上記のコードをハッキングして取得しました:

class NativeClass
{
private:
    void * managedHandle;
public:
    static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
    {
        // return NativeClass associated with SomeParameter from NativeClassHashMap;
    }
    NativeClass(void *handle, int SomeParameter)
        : managedHandle(handle)
    {
    }
    void * ManagedHandle()
    {
        return managedHandle;
    }
    void DoCalculation()
    { 
        // CALCULATIONS
    }
};

public ref class ManagedClass
{
private:
    NativeClass* _nc;
    void FreeManagedClass()
    {
        if (_nc)
        {
            // Free the handle to the managed object
            static_cast<GCHandle>(IntPtr(_nc->ManagedHandle)).Free();
            // Delete the native object
            delete _nc;
            _nc = 0;
        }
    }
public: 
    ManagedClass()
    {
        // Allocate GCHandle of type 'Normal' (see doco for Normal, Weak, Pinned)
        GCHandle gch = GCHandle::Alloc(this, GCHandleType::Normal);
        // Convert to void*
        void *handle = static_cast<IntPtr>(gch).ToPointer();
        // Initialise native object, storing handle to native object as void*
        _nc = new NativeClass(handle);
    }
    ~ManagedClass() {FreeManagedClass();}
    !ManagedClass() {FreeManagedClass();}
    static ManagedClass^ GetManagedClass(int SomeParameter)
    {
        // Native class is retrieved from hash map
        NativeClass *nc = NativeClass::GetNativeClassFromHashMap(SomeParameter);
        // Extract GCHandle from handle stored in native class
        // This is the reverse of the process used in the ManagedClass constructor
        GCHandle gch = static_cast<GCHandle>(IntPtr(nc->ManagedHandle()));
        // Cast the target of the GCHandle to the managed object
        return dynamic_cast<ManagedClass^>(gch.Target);
    }
};

これにより、正しい軌道に乗るはずです。

于 2010-11-12T12:25:23.173 に答える
0

うーん。

GCHandleは構造体です。

場合によっては、固定されていないGCHandle refを渡すと、必要な処理が実行されます。

于 2010-11-11T23:28:23.667 に答える
0

gcroot<ManagedClass^>これを非常に簡単にします

于 2010-11-11T19:06:11.327 に答える