Сложная ошибка времени выполнения при вызове собственного кода из управляемого кода - PullRequest
3 голосов
/ 01 декабря 2009

First_Layer

У меня есть win32 dll, написанная на VC ++ 6 с пакетом обновления 6. Давайте назовем эту dll как FirstLayer. У меня нет доступа к исходному коду FirstLayer, но мне нужно вызвать его из управляемого код. Проблема заключается в том, что FirstLayer интенсивно использует std :: vector и std :: string, и нет способа маршалировать эти типы напрямую в приложение C #. Код для этого уровня ниже иллюстрирует пример того, что можно найти в этой DLL.

Second_Layer

Решение, о котором я могу подумать, - это сначала создать еще одну DLL-библиотеку win32, написанную на VC ++ 6 с пакетом обновления 6. Давайте назовем эту DLL-библиотеку «SecondLayer». SecondLayer действует как оболочка для FirstLayer, которая в основном преобразует типы STL в пользовательские типы классов, не относящиеся к STL.

Third_Layer

Я также создал библиотеку классов VC ++ 2005 в качестве оболочки для SecondLayer. Эта обертка выполняет всю грязную работу по преобразованию неуправляемого SecondLayer в управляемый код. Давайте назовем этот слой «ThirdLayer». Код для этого слоя, показанный ниже, упрощен для демонстрации ошибки, поэтому он не выполняет вышеуказанное преобразование.

Fourth_Layer

В довершение всего я создал консольное приложение C # 2005 для вызова ThirdLayer. Давайте назовем это консольное приложение C # «FourthLayer».

Сводка последовательности вызовов

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

Ошибка выполнения

Приведенный ниже код компилируется / собирается без ошибок, но я получаю следующую ошибку времени выполнения:

Необработанное исключение: System.AccessViolationException: попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. в SecondLayer.PassDataBackToCaller (SecondLayer , StdVectorWrapper *) в Sample.ThirdLayer.PassDataBackToCaller () в c: \ project \ о текущих проектах \ test \ sample \ thirdlayer \ thirdlayer.cpp: строка 22 в FourthLayer.Program. Строка [] args) в C: \ Project \ Продолжающиеся проекты \ test \ Sample \ FourthLayer \ Program.cs: строка 14 *

Эта ошибка не обязательна, если приложение FourthLayer выполняется в другой операционной системе. Например, для Windows XP ошибки нет, но для других ОС, таких как Vista и Windows 7, ошибка появится.

Я не понимаю, что является причиной этого. Есть идеи? Как я могу изменить код, чтобы исправить это?

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

1 Ответ

2 голосов
/ 02 декабря 2009

Я нашел решение. По сути, с этим есть две проблемы.

Проблема первая (между FirstLayer и SecondLayer)

По умолчанию следующий параметр VC ++ 6 является многопоточным. Этот параметр должен быть изменен на многопоточный Dll для FirstLayer и SecondLayer. И то и другое необходимо перекомпилировать с этим новым параметром, чтобы он работал.

Проект-> Настройки-> Вкладка C / C ++-> Категория: Генерация кода-> Использовать библиотеку времени выполнения-> Многопоточный Dll

Проблема вторая (между SecondLayer и ThirdLayer)

Классы StdStringWrapper и StdVectorWrapper, которые я написал, не поддерживают глубокое копирование. Поэтому все, что мне нужно сделать, это добавить следующее в класс StdStringWrapper и StdVectorWrapper для реализации глубокого копирования.

  • Конструктор копирования
  • Оператор присваивания
  • Разрушитель

Редактировать: Альтернативное решение для проблемы два

Еще лучшим решением было бы использовать clone_ptr для всех элементов, содержащихся в std :: vector, а также для самого std :: vector. Это устраняет необходимость в конструкторе копирования, операторе присваивания и деконструкторе. Так что внутри класса StdVectorWrapper вы бы объявили его как

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

...