First_Layer
我有一个用VC ++ 6 Service Pack 6编写的win32 dll。让我们将这个dll称为FirstLayer。我无法访问FirstLayer的源代码,但我需要从托管代码中调用它。问题是FirstLayer大量使用std :: vector和std :: string作为函数参数,并且没有办法直接将这些类型编组到C#应用程序中。
Second_Layer
我能想到的解决方案是首先创建另一个用VC ++ 6 service pack 6编写的win32 dll。让我们将这个dll称为“SecondLayer”。 SecondLayer充当FirstLayer的包装器。该层包含std :: vector的包装类,因此std :: vector不会在此层的所有函数参数中公开。让我们将std :: vector的这个包装类称为StdVectorWrapper。
此层不使用任何新的或删除操作来分配或释放内存,因为这是由内部的std :: vector处理的。
Third_Layer
我还创建了一个VC ++ 2005类库作为SecondLayer的包装器。这个包装器完成了将非托管SecondLayer转换为托管代码的所有脏工作。我们将此图层称为“ThirdLayer”。
与SecondLayer类似,在处理StdVectorWrapper时,此图层不使用new和delete。
Fourth_Layer
最重要的是,我创建了一个C#2005控制台应用程序来调用ThirdLayer。我们将这个C#控制台应用程序称为“FourthLayer”。
通话顺序摘要
FourthLayer(C#2005) - > ThirdLayer(VC ++ 2005) - > SecondLayer(VC ++ 6) - > FirstLayer(VC 6)
问题
我注意到“ System.AccessViolationException:试图读取或写入受保护的内存”异常被抛出,我怀疑是由于SecondLayer的内部std :: vector分配内存,这是非法的ThirdLayer访问。
我认为这已得到证实,因为当我在VC ++ 2005中重新编译FirstLayer(模拟)和SecondLayer时,问题就完全消失了。但是,重新编译FirstLayer的生产版本是不可能的,因为我没有源代码。
我听说为了摆脱这个问题,我需要在C ++中为StdVectorWrapper类中的SecondLayer的std :: vector编写一个共享内存分配器。我不完全理解为什么我需要共享内存分配器及其工作原理?有什么想法吗?
互联网上有没有现成的源代码,我可以在SecondLayer中编译和使用我的代码?
请注意,我无法使用boost库。
答案 0 :(得分:0)
每个可执行文件或dll链接到特定版本的c运行时库,其中包含new
和delete
的实现。如果两个模块具有不同的编译器(VC2005与VC6)或构建设置(调试与发布)或其他设置(多线程运行时与非多线程运行时),则它们将链接到不同的c运行时。如果一个运行时分配的内存被不同的运行时释放,那就成了一个问题。
现在,如果我没有弄错的话,模板(例如std :: vector或std :: string)会导致这个问题潜入不明显的地方。问题来自于模板分别编译到每个模块中的事实。
示例:模块1使用向量(从而分配内存),然后将其作为函数参数传递给模块2,然后模块2操纵向量,从而导致内存被释放。在这种情况下,使用模块1的运行时分配内存,并使用模块2的运行时释放内存。如果这些运行时间不同,那么你就有问题了。
所以考虑到这一点,你有两个潜在问题的地方。一个是在FirstLayer和SecondLayer之间,如果这两个模块没有使用 exact 相同的设置进行编译。另一个是在SecondLayer和ThirdLayer之间,如果任何内存在一个内容中分配并在另一个内容中解除分配。
你可以写几个测试程序来确认哪个地方有问题。
要测试FirstLayer-SecondLayer,请将SecondLayer函数的实现复制到VC6程序中,编写足够的代码以典型方式调用这些函数,并仅链接到FirstLayer。
如果第一次测试没有失败,或者一旦你修复它,那么测试SecondLayer-ThirdLayer:将ThirdLayer实现复制到VC2005程序中,编写代码以进行典型调用,并链接SecondLayer。 / p>
答案 1 :(得分:0)
我认为你应该看一下不同的解决方案架构。
我相信由VC6 stl vector和string生成的二进制代码与更新版本的VC生成的代码不同,因为有许多stl升级。因此我不认为你的架构会工作,因为dll将有两个不是二进制兼容的std :: vector和std :: string实现。
我建议的解决方案是回到VC6并为FirstLayer编写一个新的包装器dll,它通过纯C API公开它 - 这个层需要使用VC6sp6进行编译,以确保它与FirstLayer二进制兼容。然后在Fourth_Layer中使用PInvoke来访问VC6包装器DLL。
答案 2 :(得分:0)
我找到了解决问题的方法。基本上,我写的StdVectorWrapper类没有实现深层复制。所以我需要做的就是将以下内容添加到StdVectorWrapper类中以实现深层复制。
编辑:替代解决方案
更好的解决方案是对std :: vector中包含的所有元素以及std :: vector本身使用clone_ptr。这消除了对复制构造函数,赋值运算符和解构函数的需要。