5

A.dllがB.dllを参照する2つのc++/ cli dll(つまり、/ clrでコンパイルされたもの)があります。アセンブリBには、メソッドGetMgdClassBがあり、アセンブリAから呼び出したいと思います。アセンブリB(B.cpp)のコードは次のとおりです。

namespace B
{
    public class NativeClassB
    {
    public:
        NativeClassB();
        // ... 
    };

    public ref class MgdClassB
    {
    public:
        static MgdClassB ^ GetMgdClassB(const std::vector<NativeClassB *> & vecNativeBs)
        {
            // ...
            vecNativeBs;
            return gcnew MgdClassB();
        }
    };
}

GetMgdClassBメソッドがstd::vectorをとることに注意してください。アセンブリAでは、次のコード(A.cpp)を使用してこのメ​​ソッドを呼び出そうとしています。

namespace B
{
    class NativeClassB;
}

#pragma make_public(std::vector<B::NativeClassB *>)

namespace A
{
    void Foo()
    {
        std::vector<B::NativeClassB *> vecNativeBs;
        B::MgdClassB::GetMgdClassB(vecNativeBs);
    }
}

A.cppをコンパイルすると、次のエラーが発生します。

error C2158: 'std::vector<_Ty>' : #pragma make_public directive is currently supported for native non-template types only

このプラグマを追加したかった理由は、ネイティブ型がデフォルトでアセンブリに対してプライベートであるためです。プラグマを削除すると、次のエラーが発生します(予想どおり)。

error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible

テンプレートのインスタンス化タイプstd::vector<B::NativeClassB *>はアセンブリ専用であるためです。

試みられた解決策

1. void *を使用し、タイプセーフティを解除します。

メソッドを変更して、GetMgdClassBを取得しvoid *、のアドレスをstd::vector<NativeClassB *>メソッドに渡します。でGetMgdClassB。その後static_cast、に渡すvoid *ことができstd::vector<NativeClassB *> *ます。もちろん、これは機能しますが、型の安全性を損ないます。

2. NativeClassBのマネージラッパーを作成し、マネージコンテナを渡します

マネージドクラスを作成します。たとえばref class NativeClassBWrapper、ネイティブのNativeClassBへの参照を保持することが唯一の目的であるとします。GetMgdClassBを変更して、NativeClassBWrappersの管理対象コンテナーを取得します(例List<NativeClassBWrapper ^> ^)。これには、GetMgdClassBを呼び出す前に新しいマネージドコンテナーを作成してデータを設定する必要があり、マネージドクラスB内で、ネイティブコンテナーに再パッケージ化する必要があるという欠点がありますstd::vector<NativeClassB *>(Bのコードはこのタイプを処理するため)。

現在、私はソリューション#1を採用する傾向にあります。これは、(a)パフォーマンスの問題が発生せず、(b)これを実行するのはごく一部の場合のみであるためです。型の安全性を失うのは好きではありませんが、ネイティブテンプレートのインスタンス化型を表示するコンパイラの機能が現在不足していることを考えると、それは正当なことのようです。

質問:

より良い回避策はありますか?

関連する質問:

C ++ CLIエラーC3767:候補関数にアクセスできません

4

2 に答える 2

2

そのタイプをエクスポートする方法を知りません。その関数シグネチャが必要な場合は、マネージ エクスポートとネイティブ エクスポートを組み合わせて使用​​する方向に傾きます (ネイティブ タイプを使用するマネージ関数は他の言語で使用できません)。ネイティブを呼び出すときに遅延読み込みを使用することもできます。エクスポートするので、通常の .NET の方法でアセンブリを見つけてエラーをトラップする機会があります。

ただし、署名でマネージド型と複雑なネイティブ型の両方を使用するため、特定の関数に問題がある可能性があります。

一般に、ベスト プラクティスは、DLL の境界を越えてネイティブ C++ クラスをまったく渡さないことです。

この特定の状況では、実装するラッパーを作成することをお勧めしますICollection。これにより、すべての要素を実際に新しいデータ構造にコピーする必要なく、ソリューション #2 と同じように問題が解決されます。

于 2010-11-08T16:28:53.027 に答える
2

別のフォーラムで Mike Danes から解決策を受け取りました。

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/b43cca63-b0bf-451e-b8fe-74e9c618b8c4/

基本的に、解決策は、std::vector へのポインターまたは参照を保持するアセンブリ B にネイティブ ラッパー (VectorOfNativeB と呼びます) を作成することです。VectorOfNativeB をエクスポートして公開します。メソッド GetMgdClassB を変更して、ポインターを取得するか、VectorOfNativeB を参照します。

[今後の参考のためにここに投稿し、このソリューションについてコメントがあるかどうかを確認します]。

于 2010-11-09T21:02:14.750 に答える