2009-12-01 6 views
3

First_LayerErreur d'exécution lors de l'appel Contestation code natif du code managé

J'ai un dll win32 écrit en service pack VC++ 6 6. Appelons cette dll comme FirstLayer. Je n'ai pas accès au code source de FirstLayer mais je dois l'appeler à partir du code géré. Le problème est que FirstLayer fait un usage intensif de std :: vector et de std :: string et qu'il n'y a aucun moyen de rassembler ces types directement dans une application C#. Le code pour cette couche ci-dessous illustre un exemple de ce qui peut être trouvé dans cette DLL.

Second_Layer

La solution que je peux penser est d'abord créer un autre dll win32 écrit en service pack VC++ 6 6. Appelons cette dll comme "SecondLayer". SecondLayer agit comme un wrapper pour FirstLayer qui convertit fondamentalement les types STL en types de classes écrites non STL.

Third_Layer

J'ai aussi créé une bibliothèque de classes VC++ 2005 comme une enveloppe pour SecondLayer. Ce wrapper fait tout le sale boulot de la conversion de SecondLayer non managé en code managé. Appelons cette couche "ThirdLayer". Le code de cette couche, comme indiqué ci-dessous, est simplifié pour illustrer l'erreur, de sorte qu'il ne fait pas la conversion mentionnée ci-dessus.

Fourth_Layer

Pour couronner le tout, j'ai créé une application console C# 2005 pour appeler ThirdLayer. Appelons cette application console C# "FourthLayer".

Séquence d'appel Résumé

FourthLayer (C# 2005) -> ThirdLayer (VC++ 2005) -> SecondLayer (VC++ 6) -> FirstLayer (VC++ 6)

l'erreur d'exécution

le code ci-dessous compilez/build sans erreurs mais je reçois l'erreur d'exécution suivante:

Exception non gérée: System.AccessViolatio nException: tentative de lecture ou d'écriture de mémoire protégée. C'est souvent une indication que l'autre mémoire est corrompue. à SecondLayer.PassDataBackToCaller (SecondLayer, StdVectorWrapper *) à Sample.ThirdLayer.PassDataBackToCaller() dans c: \ projet \ sur les projets en cours \ test \ sample \ thirdlayer \ thirdlayer.cpp: ligne 22 à FourthLayer.Program.Main (String [ ] args) dans C: \ Projet \ sur les projets en cours \ test \ Sample \ FourthLayer \ Program.cs: ligne 14 *

Cette erreur n'apparaît pas nécessairement lorsque l'application FourthLayer est exécutée sur un système d'exploitation différent. Par exemple, pour Windows XP, il n'y a pas d'erreur mais pour les autres systèmes d'exploitation comme Vista et Windows 7, l'erreur apparaîtra.

Je ne comprends pas ce qui cause cela. Des idées? Comment puis-je modifier le code pour corriger cela?

// Fourth_Layer (application console C# 2005)

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

// Third_Layer (VC++ 2005 bibliothèque 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 - Principale (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 classe (VC++ 6 dll win32)

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 classe (dll VC++ 6 win32)

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

Répondre

2

J'ai trouvé la solution. Bascially, il y a deux problèmes avec cela.

problème Un (entre FirstLayer et SecondLayer)

Par défaut, le paramètre suivant de VC++ 6 est multithread. Ce paramètre doit être modifié en Dll multithread pour FirstLayer et SecondLayer. Les deux doivent être recompilées avec ce nouveau paramètre pour que cela fonctionne.

Projet-> Paramètres-> C/C++ tab-> Catégorie: Code génération-> Utiliser run-time Library-> multithread dll

Problème Deux (entre SecondLayer et ThirdLayer)

Le La classe StdStringWrapper et StdVectorWrapper que j'ai écrite n'implémente pas de copie en profondeur. Donc tout ce que je dois faire est d'ajouter ce qui suit à la classe StdStringWrapper et StdVectorWrapper pour implémenter une copie en profondeur.

  • Constructor Copie
  • opérateur d'affectation
  • Deconstructor

Edit: Solution alternative pour problème Deux

Une solution encore meilleure serait d'utiliser clone_ptr pour tous les éléments contenus dans std :: vector ainsi que pour std :: vector lui-même. Ceci élimine le besoin du constructeur de copie, de l'opérateur d'assignation et du déconstructeur. Donc, à l'intérieur de la classe StdVectorWrapper, vous le déclarez comme

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

Questions connexes