Обработка неуправляемой строки в оболочке C ++ / CLI - BLOCK_TYPE_IS_VALID, _CrtIsValidHeapPointer - PullRequest
4 голосов
/ 11 апреля 2011

Я новичок в C ++ / CLI, но кодирую управляемый код много лет ... очевидно, слишком много лет. :)

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

CLI Wrapper:

public ref class Wrapper
{
public:
    Wrapper(const float* flts, unsigned int fltlen, int offset)
    {
        _unmanagedClass = new UnmanagedClass(flts, fltlen, offset);
    }

    ~Wrapper()
    {
        delete _unmanagedClass;
    }

    String^ getSomeString()
    {
        string x = _unmanagedClass->getSomeString(); //1
        String^ ret = gcnew String(x.c_str()); //2
        return ret; //3
    }

private:
    UnmanagedClass* _unmanagedClass;
};

Я должен также отметить, что у меня есть эти директивы в заголовке;

#pragma managed(push, off)
#include "Unmanaged.h"
#pragma comment(lib, "lib\\Unmanaged_dll.lib")
#pragma managed(pop)

Вот неуправляемый.h;

class UNMANGED_API UnmanagedClass
{
public:
    UnmanagedClass(const float* flts, uint fltlen, int offset);
    string getSomeString() { return _someString; }

private:
    string _someString;
};

Это все компилируется. Затем проявляется странность / отсутствие опыта.

При отладке в конфигурации DEBUG UnmanagedClass::getSomeString() возвращает возвращаемое / ожидаемое строковое значение. Я могу видеть это, установив точку останова на //2 и посмотрев значение x. Если я перейду к //3, я увижу, что ret имеет значение x. Однако, если я попытаюсь выйти за пределы //3, я получу пару неудачных утверждений (BLOCK_TYPE_IS_VALID и _CrtIsValidHeapPointer), и отладчик остановится, никогда не возвращаясь к управляемой реализации.

При отладке этого в конфигурации RELEASE я не получаю ошибочные утверждения и возвращаюсь к своей управляемой реализации, но строковое значение, возвращаемое getSomeString(), является мусором, где бы я ни заглядывал; //2, //3, а также в управляемой реализации.

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

Я думаю, что есть кое-что, что нужно сделать в районе //2, но я не смог найти ничего, что по-настоящему ударит по дому, в том, что касается маршаллинга этого basic_string в System::String^, или если это даже требуется. Если это так, то некоторая помощь с явным синтаксисом будет принята с благодарностью.

Я также сузил вызов, который выдает ошибочные утверждения, до //1, возвращая return ""; //3. Эти утверждения указывают на попытку изменить / удалить память, которой не существует в куче, к которой имеет доступ текущая среда выполнения. Связано ли это с необходимостью маршалирования возвращаемого значения UnmangedClass::getSomeString()?

Надеюсь, я просто упускаю здесь простую концепцию, и нет проблем со сторонним кодом. Пожалуйста, дайте мне знать, если я могу предоставить более подробную информацию и извинения за почти полное незнание дедушки всех языков.

Заранее спасибо за любую информацию или "указатели";

EDIT: добавление C # управляемой реализации клиента;

public unsafe string GetString(List<float> flts )
{
    float[] fltArr = flts.ToArray();

    Wrapper wrap;

    fixed (float* ptrFlts = fltArr)
    {
        wrap = new Wrapper(ptrFlts , fltArr.Length, 0);
    }

    var x = wrap.getSomeString();
    return x.ToString();
}

РЕДАКТИРОВАТЬ: Добавление подписи Dumpbin.exe Unmanged.dll! UnmangedClass :: getSomeString ()

(public: class std::basic_string<code><char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Codegen :: getSomeString (void))

Ответы [ 2 ]

2 голосов
/ 11 апреля 2011

Эта проблема не имеет ничего общего с .NET или C ++ / CLI, проблема только в собственном коде.

Вы нарушили Правило единого определения для std::string, если ваше определение не 'Точно совпадает с тем, что использует Unmanaged_dll.dll, все адские прорывы ослабевают.И это звучит так, как будто эта DLL используется для определения отладки / макета класса.

1 голос
/ 11 апреля 2011

Вы отлично преобразовали свою нативную строку в управляемую.В этой статье на MSDN приведены примеры того, как конвертировать все типы строк, поставляемые на платформах Microsoft:

Сказав это, я взял ваш код и скомпилировал его, и яне мог ничего потерпеть неудачу.Конечно, мне пришлось придумать свой собственный способ инициализации UnmanagedClass :: _ someString, который я сделал, просто сделав это:

UnmanagedClass::UnmanagedClass(const float* /*flts*/, unsigned int /*fltlen*/, int /*offset*/)
{
    _someString = "A few of my favorite things";
}

Когда я это сделал, и прошел по коду:

#include "stdafx.h"
#include "Wrapper.h"

int _tmain(int argc, _TCHAR* argv[])
{
    Wrapper^ w = gcnew Wrapper(NULL, 0, 0);
    System::String^ s = w->getSomeString();
    return 0;
}

Работало просто отлично.Вот остальное, что я сделал:

// UnmanagedClass.h
#pragma once
#pragma unmanaged
#include <vector>

class UnmanagedClass
{
public:
    UnmanagedClass(const float* flts, unsigned int fltlen, int offset);
    std::string getSomeString() { return _someString; }
private:
    std::string _someString;
};

И его реализация:

// UnmanagedClass.cpp
#include "UnmanagedClass.h"
#include <tchar.h>

UnmanagedClass::UnmanagedClass(const float* /*flts*/, unsigned int /*fltlen*/, int /*offset*/)
{
    _someString = "A few of my favorite things";
}

И управляемый класс

// wrapper.h
#pragma once

#pragma unmanaged
#include "UnmanagedClass.h"

#pragma managed

public ref class Wrapper
{
public:
    Wrapper(const float* flts, unsigned int fltlen, int offset)
    {
        _unmanagedClass = new UnmanagedClass(flts, fltlen, offset);
    }

    ~Wrapper()
    {
        delete _unmanagedClass;
    }

    System::String^ getSomeString()
    {
        std::string x = _unmanagedClass->getSomeString(); //1
        System::String^ ret = gcnew System::String(x.c_str()); //2
        return ret; //3
    }
private:
    UnmanagedClass* _unmanagedClass;
};

Надеюсь, это немного поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...