Вызов ошибки времени выполнения при вызове собственного кода из управляемого кода

Первый_слой

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

Второй_слой

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

Третий_слой

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

Четвертый_слой

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

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

Четвертый уровень (C#2005) -> Третий уровень (VC++2005) -> Второй уровень (VC++6) -> Первый уровень (VC++6)

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

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

Необработанное исключение: System.AccessViolationException: попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена. в SecondLayer.PassDataBackToCaller(SecondLayer, StdVectorWrapper*) в Sample.ThirdLayer.PassDataBackToCaller() в c:\project\ongoing tools\test\sample\ Thirdlayer\ Thirdlayer.cpp:строка 22 в FourthLayer.Program.Main (аргументы String[]) в C:\Project\On Going Projects\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);
}

person Lopper    schedule 01.12.2009    source источник


Ответы (1)


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

Проблема 1 (между первым и вторым слоями)

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

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

Проблема вторая (между вторым и третьим слоями)

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

  • Копировать конструктор
  • Оператор присваивания
  • Деконструктор

Изменить: Альтернативное решение второй проблемы

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

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

person Lopper    schedule 02.12.2009