3

First_Layer

VC++6 サービス パック 6 で書かれた win32 dll があります。この dll を FirstLayer と呼びましょう。FirstLayer のソース コードにアクセスできませんが、マネージ コードから呼び出す必要があります。問題は、FirstLayer が std::vector と std::string を多用し、これらの型を C# アプリケーションに直接マーシャリングする方法がないことです。以下のこのレイヤーのコードは、この dll に含まれる内容の例を示しています。

Second_Layer

私が考えることができる解決策は、最初に VC++6 サービス パック 6 で記述された別の win32 dll を作成することです。この dll を「SecondLayer」と呼びましょう。SecondLayer は、基本的に STL 型をカスタムで記述された非 STL クラス型に変換する FirstLayer のラッパーとして機能します。

サードレイヤー

また、SecondLayer のラッパーとして VC++2005 クラス ライブラリを作成しました。このラッパーは、アンマネージ SecondLayer をマネージ コードに変換するという面倒な作業をすべて行います。この層を「ThirdLayer」としましょう。以下に示すこのレイヤーのコードは、エラーを示すために簡略化されているため、上記の変換は行われません。

四層目

さらに、ThirdLayer を呼び出す C#2005 コンソール アプリケーションを作成しました。この C# コンソール アプリケーションを「FourthLayer」と呼びましょう。

呼び出しシーケンスの概要

4 層目 (C#2005) -> 3 層目 (VC++2005) -> 2 層目 (VC++6) -> 1 層目 (VC++6)

実行時エラー

以下のコードはエラーなしでコンパイル/ビルドされますが、次のランタイム エラーが発生します。

未処理の例外: System.AccessViolationException: 保護されたメモリの読み取りまたは書き込みを試みました。これは多くの場合、他のメモリが破損していることを示しています。SecondLayer.PassDataBackToCaller(SecondLayer ,StdVectorWrapper* ) at Sample.ThirdLayer.PassDataBackToCaller() in c:\project\on going projects\test\sample\thirdlayer\thirdlayer.cpp:line 22 at FourthLayer.Program.Main(String[] args) in C:\Project\On Going Projects\test\Sample\FourthLayer\Program.cs:line 14*

このエラーは、FourthLayer アプリケーションが別のオペレーティング システムで実行されている場合には表示されません。たとえば、Windows XP ではエラーは発生しませんが、Vista や Windows 7 などの他の OS ではエラーが表示されます。

何が原因なのかわかりません。何か案は?これを修正するためにコードを変更するにはどうすればよいですか?

// Fourth_Layer (C#2005 コンソール アプリケーション)

class FourthLayer
{
    static void Main(string[] args)
    {
        ThirdLayer thirdLayer = new ThirdLayer();
        thirdLayer.PassDataBackToCaller();
    }
}

// Third_Layer (VC++2005 クラス ライブラリ)

public ref class ThirdLayer
{
    private:
        SecondLayer *_secondLayer;

    public:
        ThirdLayer();
        ~ThirdLayer();
        void PassDataBackToCaller();
};

ThirdLayer::ThirdLayer()
{
    _secondLayer = new SecondLayer();
}

ThirdLayer::~ThirdLayer()
{
    delete _secondLayer;
}

void ThirdLayer::PassDataBackToCaller()
{ 
    StdVectorWrapper v;
    _secondLayer->PassDataBackToCaller(v);

    for (int i=0; i<v.GetSize(); i++)
    {
        StdStringWrapper s = v.GetNext();
        std::cout << s.CStr() << std::endl;
    }
}

// Second_Layer - メイン クラス (VC++6 win32 dll)

class SECOND_LAYER_API SecondLayer
{
    private:
        FirstLayer *_firstLayer;

    public:
        SecondLayer();
        ~SecondLayer();
        void PassDataBackToCaller(StdVectorWrapper &toCaller);

    private:
        void ConvertToStdVectorWrapper(
            const std::vector<std::string> &in, StdVectorWrapper &out);
};

SecondLayer::SecondLayer() : _firstLayer(new FirstLayer())
{
}

SecondLayer::~SecondLayer()
{
    delete _firstLayer;
}

void SecondLayer::PassDataBackToCaller(StdVectorWrapper &toCaller)
{ 
    std::vector<std::string> v;
    _firstLayer->PassDataBackToCaller(v);
    ConvertToStdVectorWrapper(v, toCaller);
}

void SecondLayer::ConvertToStdVectorWrapper(
    const std::vector<std::string> &in, StdVectorWrapper &out)
{
    for (std::vector<std::string>::const_iterator it=in.begin(); it!=in.end(); ++it)
    {
        StdStringWrapper s((*it).c_str());
        out.Add(s);
    }
}

// Second_Layer - StdVectorWrapper クラス (VC++6 win32 dll)

class SECOND_LAYER_API StdVectorWrapper
{
    private:
        std::vector<StdStringWrapper> _items;
        int index;  

    public: 
        StdVectorWrapper();
        void Add(const StdStringWrapper& item);
        int GetSize() const;  
        StdStringWrapper& GetNext(); 
};

StdVectorWrapper::StdVectorWrapper()
{
    index = 0;
}

void StdVectorWrapper::Add(const StdStringWrapper &item)
{
    _items.insert(_items.end(),item);
}

int StdVectorWrapper::GetSize() const
{
    return _items.size();
}

StdStringWrapper& StdVectorWrapper::GetNext()
{
    return _items[index++];
}

// Second_Layer - StdStringWrapper クラス (VC++6 win32 dll)

class SECOND_LAYER_API StdStringWrapper
{
    private:
        std::string _s;

    public:  
        StdStringWrapper();
        StdStringWrapper(const char *s);
        void Append(const char *s);
        const char* CStr() const;  
};

StdStringWrapper::StdStringWrapper()
{
}

StdStringWrapper::StdStringWrapper(const char *s)
{
    _s.append(s);
}

void StdStringWrapper::Append(const char *s)
{
    _s.append(s);
}

const char* StdStringWrapper::CStr() const
{
    return _s.c_str();
}

// First_Layer (VC++6 win32 dll)

class FIRST_LAYER_API FirstLayer
{
    public:
        void PassDataBackToCaller(std::vector<std::string> &toCaller);
};

void FirstLayer::PassDataBackToCaller(std::vector<std::string> &toCaller)
{
    std::string a, b;
    a.append("Test string 1"); 
    b.append("Test string 2");
    toCaller.insert(toCaller.begin(),a);
    toCaller.insert(toCaller.begin(),b);
}
4

1 に答える 1

2

解決策を見つけました。基本的に、それには2つの問題があります。

問題 1 (FirstLayer と SecondLayer の間)

デフォルトでは、VC++6 の次の設定はマルチスレッドです。この設定は、FirstLayer と SecondLayer の両方でマルチスレッド DLL に変更する必要があります。どちらも、この新しい設定で再コンパイルする必要があります。

[プロジェクト] -> [設定] -> [C/C++] タブ -> [カテゴリ: コード生成] -> [ランタイム ライブラリを使用] -> [マルチスレッド DLL]

問題 2 (SecondLayer と ThirdLayer の間)

私が書いた StdStringWrapper と StdVectorWrapper クラスはディープコピーを実装していません。したがって、ディープ コピーを実装するために、StdStringWrapper および StdVectorWrapper クラスに以下を追加するだけです。

  • コンストラクターのコピー
  • 代入演算子
  • デコンストラクター

編集:問題2の代替ソリューション

さらに良い解決策は、std::vector 自体だけでなく、std::vector に含まれるすべての要素に対してclone_ptrを使用することです。これにより、コピー コンストラクター、代入演算子、およびデコンストラクターが不要になります。したがって、StdVectorWrapper クラス内では、次のように宣言します。

clone_ptr< std::vector< clone_ptr< StdStringWrapper > > > _items;

于 2009-12-02T13:19:45.817 に答える