从托管代码调用本机代码时具有挑战性的运行时错误

时间:2009-12-01 13:31:52

标签: c# c++ dll visual-studio-2005 runtime-error

First_Layer

我有一个用VC ++ 6 Service Pack 6编写的win32 dll。让我们将这个dll称为FirstLayer。我无法访问FirstLayer的源代码,但我需要从托管中调用它 码。问题是FirstLayer大量使用std :: vector和std :: string,并且没有办法直接将这些类型封送到C#应用程序中。下面这一层的代码说明了可以在此dll中找到的内容的示例。

Second_Layer

我能想到的解决方案是首先创建另一个用VC ++ 6 service pack 6编写的win32 dll。让我们将这个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:\项目\要去项目\测试\样品\ thirdlayer \ thirdlayer.cpp:线22在FourthLayer.Program.Main (String [] args)in 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);
}

1 个答案:

答案 0 :(得分:2)

我找到了解决方案。基本上,它存在两个问题。

问题一(在FirstLayer和SecondLayer之间)

默认情况下,VC ++ 6的以下设置为Multithreaded。对于FirstLayer和SecondLayer,此设置必须更改为Multithreaded Dll。必须使用这个新设置重新编译这两个设置才能工作。

项目 - &gt;设置 - &gt; C / C ++标签 - &gt;类别:代码生成 - &gt;使用运行时库 - &gt;多线程Dll

问题二(在SecondLayer和ThirdLayer之间)

我写的StdStringWrapper和StdVectorWrapper类没有实现深层复制。所以我需要做的就是将以下内容添加到StdStringWrapper和StdVectorWrapper类中以实现深层复制。

  • 复制构造函数
  • 作业运营商
  • 拆解

编辑:问题二的替代解决方案

更好的解决方案是对std :: vector中包含的所有元素以及std :: vector本身使用clone_ptr。这消除了对复制构造函数,赋值运算符和解构函数的需要。因此,在StdVectorWrapper类中,您将其声明为

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