1

第一层

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

第二层

我能想到的解决方案是先创建另一个用VC++6 service pack 6编写的win32 dll。我们把这个dll称为“SecondLayer”。SecondLayer 充当 FirstLayer 的包装器。该层包含 std::vector 的包装类,因此 std::vector 不会在该层的所有函数参数中公开。我们将 std::vector 的这个包装类称为 StdVectorWrapper。

该层不使用任何新的或删除的操作来分配或释放内存,因为这是由 std::vector 内部处理的。

第三层

我还创建了一个 VC++2005 类库作为 SecondLayer 的包装器。这个包装器完成了将非托管 SecondLayer 转换为托管代码的所有繁琐工作。让我们将此层称为“ThirdLayer”。

与 SecondLayer 类似,该层在处理 StdVectorWrapper 时不使用 new 和 delete。

第四层

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

调用序列摘要

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

问题

我注意到“ System.AccessViolationException: Attempted to read or write protected memory ”异常被抛出,我怀疑这是由于 SecondLayer 的内部 std::vector 分配内存,这对于 ThirdLayer 访问是非法的。

我认为这得到了证实,因为当我在 VC++2005 中重新编译 FirstLayer(模拟)和 SecondLayer 时,问题完全消失了。但是,无法重新编译 FirstLayer 的生产版本,因为我没有源代码。

我听说为了摆脱这个问题,我需要在 C++ 中为在 StdVectorWrapper 类中找到的 SecondLayer 的 std::vector 编写一个共享内存分配器。我不完全理解为什么我需要一个共享内存分配器以及它是如何工作的?任何的想法?

互联网上是否有任何现成的源代码可以编译并与我在 SecondLayer 中的代码一起使用?

请注意,我无法为此使用 boost 库。

4

3 回答 3

0

每个可执行文件或 dll 都链接到特定版本的 c 运行时库,其中包含 和 的new实现delete。如果两个模块具有不同的编译器(VC2005 与 VC6)或构建设置(调试与发布)或其他设置(多线程运行时与非多线程运行时),那么它们将链接到不同的 c 运行时。如果一个运行时分配的内存被另一个运行时释放,这就会成为一个问题。

现在,如果我没记错的话,模板(例如 std::vector 或 std::string)可能会导致这个问题潜入不明显的地方。问题来自模板分别编译到每个模块中的事实。

示例:模块 1 使用向量(从而分配内存),然后将其作为函数参数传递给模块 2,然后模块 2 操作向量导致内存被释放。在这种情况下,内存是使用模块 1 的运行时分配的,并使用模块 2 的运行时释放。如果这些运行时不同,那么您就有问题了。

因此,考虑到所有这些,您有两个潜在问题的地方。如果这两个模块没有使用完全相同的设置编译,则一个位于 FirstLayer 和 SecondLayer 之间。另一个在 SecondLayer 和 ThirdLayer 之间,如果任何内存在一个中分配并在另一个中释放。

您可以编写更多测试程序来确认哪些地方有问题。

要测试 FirstLayer-SecondLayer,请将 SecondLayer 函数的实现复制到 VC6 程序中,编写足够的代码以以典型方式调用这些函数,并仅链接 FirstLayer。

如果第一个测试没有失败,或者一旦你修复它,然后测试 SecondLayer-ThirdLayer:将 ThirdLayer 实现复制到 VC2005 程序中,编写代码以进行典型调用,并链接到 SecondLayer。

于 2009-12-06T03:36:22.750 回答
0

我认为您应该查看不同的解决方案架构。

由于许多 stl 升级,VC6 stl 向量和字符串生成的二进制代码与最新版本的 VC 生成的代码不同。因此,我认为您的架构不会工作,因为 dll 将具有两个不兼容二进制的 std::vector 和 std::string 实现。

我建议的解决方案是回到 VC6 并为 FirstLayer 编写一个新的包装 dll,通过纯 C API 公开它——该层需要使用 VC6sp6 编译以确保它与 FirstLayer 二进制兼容。然后使用 Fourth_Layer 中的 PInvoke 访问 VC6 包装 DLL。

于 2009-12-09T02:15:09.643 回答
0

我找到了解决问题的方法。基本上,我写的 StdVectorWrapper 类没有实现深拷贝。所以我需要做的就是在 StdVectorWrapper 类中添加以下内容来实现深拷贝。

  • 复制构造函数
  • 赋值运算符
  • 解构器

编辑:替代解决方案

更好的解决方案是将clone_ptr用于 std::vector 中包含的所有元素以及 std::vector 本身。这消除了对复制构造函数、赋值运算符和解构函数的需要。

于 2009-12-09T08:06:49.017 回答