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);
}