3

第一层

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

第二层

我能想到的解决方案是先创建另一个用VC++6 service pack 6编写的win32 dll。我们把这个dll称为“SecondLayer”。SecondLayer 充当 FirstLayer 的包装器,它基本上将 STL 类型转换为自定义编写的非 STL 类类型。

第三层

我还创建了一个 VC++2005 类库作为 SecondLayer 的包装器。这个包装器完成了将非托管 SecondLayer 转换为托管代码的所有繁琐工作。让我们将此层称为“ThirdLayer”。如下所示的该层的代码被简化以演示错误,因此它不进行上述转换。

第四层

最重要的是,我创建了一个 C#2005 控制台应用程序来调用 ThirdLayer。让我们将此 C# 控制台应用程序称为“FourthLayer”。

调用序列摘要

第四层(C#2005) -> 第三层(VC++2005) -> 第二层(VC++6) -> 第一层(VC++6)

运行时错误

下面的代码编译/构建没有错误,但我收到以下运行时错误:

未处理的异常:System.AccessViolationException:试图读取或写入受保护的内存。这通常表明其他内存已损坏。在 SecondLayer.PassDataBackToCaller(SecondLayer ,StdVectorWrapper* ) 在 Sample.ThirdLayer.PassDataBackToCaller() 在 c:\project\on going projects\test\sample\thirdlayer\thirdlayer.cpp:line 22 at FourthLayer.Program.Main(String[] args) 在 C:\Project\On Going Projects\test\Sample\FourthLayer\Program.cs:line 14*

在不同操作系统上执行 FourthLayer 应用程序时,不会出现此错误。例如,对于 Windows XP,没有错误,但对于 Vista 和 Windows 7 等其他操作系统,则会出现错误。

我不明白是什么原因造成的。有任何想法吗?我该如何修改代码来纠正这个问题?

// Fourth_Layer (C#2005 console application)

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

// Third_Layer (VC++2005 class library)

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 - Main Class (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 Class (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 Class (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);
}
4

1 回答 1

2

I found the solution. Bascially, there are two problems with it.

Problem One (Between FirstLayer and SecondLayer)

By default, the following setting of VC++6 is Multithreaded. This setting have to be changed to Multithreaded Dll for both the FirstLayer and SecondLayer. Both of which must be re-compiled with this new setting for it to work.

Project->Settings->C/C++ Tab->Category: Code Generation->Use run-time library->Multithreaded Dll

Problem Two (Between SecondLayer and ThirdLayer)

The StdStringWrapper and StdVectorWrapper class which I wrote do not implement deep copy. So all I need to do is to add the following to the StdStringWrapper and StdVectorWrapper class to implement deep copy.

  • Copy Constructor
  • Assignment Operator
  • Deconstructor

Edit: Alternative Solution for Problem Two

An even better solution would be to use clone_ptr for all the elements contained in std::vector as well as for std::vector itself. This eliminates the need for the copy constructor, assignment operator and deconstructor. So inside the StdVectorWrapper class, you would declare it as

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

于 2009-12-02T13:19:45.817 回答