Desafiando Runtime Erro ao chamar código nativo de código gerenciado
-
22-07-2019 - |
Pergunta
First_Layer
Eu tenho um dll win32 escrito em VC ++ 6 Service Pack 6. Vamos chamada esta dll como FirstLayer. Eu não tenho acesso ao código fonte do FirstLayer mas eu preciso chamá-lo de gerenciado código. O problema é que FirstLayer faz uso pesado de std :: vector e std :: string e não há nenhuma maneira de empacotamento desses tipos em um aplicativo C # diretamente. O código para esta camada abaixo ilustra um exemplo do que pode ser encontrado neste dll.
Second_Layer
A solução que eu posso pensar é a primeira a criar outra dll win32 escrito em VC ++ 6 Service Pack 6. Vamos chamada esta dll como "SecondLayer". SecondLayer atua como um wrapper para FirstLayer que basicamente converte tipos de STL em tipos não de classe STL personalizados escrito.
Third_Layer
Eu também criou um VC ++ biblioteca de classe 2005 como um wrapper para SecondLayer. Este invólucro faz todo o trabalho sujo de converter o SecondLayer não gerenciado em código gerenciado. Vamos chamar essa camada como "ThirdLayer". O código para esta camada como mostrado abaixo é simplificada para demonstrar o erro de modo que não fazer a conversão acima mencionada.
Fourth_Layer
Para cima de tudo, eu criei um C # 2005 aplicativo de console para chamar ThirdLayer. Vamos chamar esse aplicativo de console C # como "FourthLayer".
Resumo de chamadas Sequence
FourthLayer (C # 2005) -> ThirdLayer (VC ++ 2005) -> SecondLayer (VC ++ 6) -> FirstLayer (VC ++ 6)
O erro de execução
O código abaixo compilação / compilação sem erros, mas eu recebo o seguinte erro de tempo de execução:
Exceção não tratada: System.AccessViolationException: Tentativa de ler ou memória protegida gravação. Isso é muitas vezes uma indicação de que outra memória está corrompida. em SecondLayer.PassDataBackToCaller (SecondLayer , StdVectorWrapper *) em Sample.ThirdLayer.PassDataBackToCaller () em c: \ project \ em ir teste projetos \ \ sample \ thirdlayer \ thirdlayer.cpp: linha 22 em FourthLayer.Program.Main (String [] args) em C: \ Project \ Going On Projects \ test \ Sample \ FourthLayer \ Program: linha 14 *
Este erro não é necessário que aparecem quando a aplicação FourthLayer é executado no sistema operacional diferente. Por exemplo, para o Windows XP, há nenhum erro, mas por outro sistema operacional como o Vista e Windows 7, o erro vai aparecer.
Eu não entendo o que está causando isso. Alguma ideia? Como posso ir sobre como modificar o código para corrigir isso?
// Fourth_Layer (C # 2005 aplicativo console)
class FourthLayer
{
static void Main(string[] args)
{
ThirdLayer thirdLayer = new ThirdLayer();
thirdLayer.PassDataBackToCaller();
}
}
// Third_Layer (VC ++ 2005 biblioteca de classes)
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 - classe principal (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 Class (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 Class (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);
}
Solução
Eu encontrei a solução. Bascially, existem dois problemas com ele.
Problema One (Entre FirstLayer e SecondLayer)
Por padrão, a seguinte configuração de VC ++ 6 é multithread. Esta definição tem de ser alterado para Multithreaded DLL para tanto o FirstLayer e SecondLayer. Ambos os quais deve ser com esta nova configuração para que ele funcione compilado-re.
Projeto-> Configurações> C / C ++ tabulação> Categoria: Código Generation-> Use run-time biblioteca-> Multithreaded DLL
Problema Two (Entre SecondLayer e ThirdLayer)
A classe StdStringWrapper e StdVectorWrapper que eu escrevi não implementar cópia profunda. Então tudo necessidade I a fazer é adicionar a seguinte para a classe StdStringWrapper e StdVectorWrapper para implementar cópia profunda.
- Construtor de cópia
- Operador de atribuição
- Deconstructor
Editar: Solução Alternativa para o problema Two
Um ainda melhor solução seria usar clone_ptr para todos os elementos contidos no std :: vector, bem como para std :: próprio vector. Isso elimina a necessidade do construtor de cópia, operador de atribuição e deconstructor. Então, dentro da classe StdVectorWrapper, você declará-lo como
clone_ptr< std::vector< clone_ptr< StdStringWrapper > > > _items;