本机 C 的 C++/CLI 包装器中的 AccesViolationException
AccesViolationException in C++/CLI Wrapper for native C
我正在用 C# 编写一个应用程序,它使用 C++/CLI Wrapper .dll,它再次使用另一个 C++/CLI Wrapper 用于本机 C 代码。
进一步说明:
我的 C# 应用程序(我称之为 Reporter)只不过是一个 windows 表单,它调用第一个包含 UserControl 的 C++/CLI Wrapper(我称之为 Control)。此 UserControl 是一个 GUI,以便调用最后一个 .dll(称为 Generator)。我这样做是因为我想在其他项目中使用我的控件,并且我不想像 char *
.
这样的类型编组麻烦
所以这是我的问题:有时我可以按计划调用生成器函数。但是在一些调用之后,我得到一个 AccessViolationException。
我的生成器包含大量 C 函数和全局 C 变量。一切都正确标记为 extern "C"
。正如我所确定的,当我尝试使用全局变量时会发生违规。
我试图将所有全局变量放入生成器中的包装器-class,但我失败了,因为我无法将所有 C 类型转换为托管类型。
调用函数后,我 free(x)
正在 space 我的变量。在评论之前,我无法调用该函数两次以上。现在(注释掉之后)我可以调用 Generator 中的函数 4 次。总是。
我该如何解决这个问题?有没有办法像 "administrative rights" 那样提供我的函数,以允许他们使用全局变量做他们想做的事情?
提前感谢大家,我坚持了将近一个月,并且对如何编写 wrapper-classes 做了很多研究。
里昂
编辑:
这是我声明相关全局变量的方式:
"globals.h"
extern "C"{
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // fuer va_start, va_end
#include <string.h>
#include <malloc.h>
#include <windows.h>
//#include <omp.h>
// Used to prevent redefinition, _HAUPT_ is only defined in .dll-Header
#ifdef _HAUPT_
/*#define _HAUPT_*/
#define TYPE
int extreme = 0;
#else
#define TYPE extern
TYPE int extreme;
#endif
}
然而,当我在这里写我的编辑时,我发现问题出在我这边。我搞混了一个自己写的LinkedList
,当我试图用一个值声明一个未分配的指针时发生错误
对于这样的问题,您无法得到有用的答案。访问冲突是 C 代码失败的标准方式,在该语言中有许多方法可以调用未定义的行为。破坏内存的那种,这种破坏 最终 会使您的代码崩溃。代码失败的确切位置是 非常 很少接近有错误的语句。腐败产生影响可能需要一段时间。花一个星期或更长时间来查找错误一点也不稀奇。
基本方法:
- 编写运行 C 代码的单元测试,有助于缩小导致损坏的代码执行路径的数量。
- 确保在打开所有调试功能的情况下构建 C 代码,默认情况下为 MSVC 编译器中的调试构建启用。您需要从 /MDd 和 /RTC 获得的所有帮助。
- 使用 Application Verifier,一种可以检测堆损坏并向您显示导致损坏的语句的工具。最好用于失败的单元测试。
- 想想C语言是否真的对你完成工作有用。与托管代码相比,您可以从本机代码中挤出大约 25% 的额外性能,给予或索取,但如果您不能使其可靠地工作或失去一个月的生命,那么代价是相当高的。硬件比您的工时便宜很多。
我同意 Taus 的观点:
AccessViolationExceptions
are most often caused by accessing
freed/unallocated memory or similar. Admin rights have nothing to do
with it. A minimal example would go along way towards identifying the
problem
封送拆收器通常会尝试创建该数据的托管 (C#) 表示,然后尝试 deallocate/free 非托管数据 (C++)。但是,您可能没有按照编组器期望的方式在 C/C++ 中分配内存,或者您可能不希望编组器尝试为您释放内存。
如果默认的解除分配行为与您的用例不匹配,那么您可以通过在 C# 代码中使用 IntPtr
手动处理 C++ 对象的解除分配(如果有的话)。例如,如果您从非托管代码返回字符串文字,则不应释放内存。请参阅此 post 示例。
如果您 post 显示您如何在非托管应用程序中分配内存、如何公开数据以及如何在 C# 应用程序中访问它的代码片段,我们可以帮助您查明问题。
我正在用 C# 编写一个应用程序,它使用 C++/CLI Wrapper .dll,它再次使用另一个 C++/CLI Wrapper 用于本机 C 代码。
进一步说明:
我的 C# 应用程序(我称之为 Reporter)只不过是一个 windows 表单,它调用第一个包含 UserControl 的 C++/CLI Wrapper(我称之为 Control)。此 UserControl 是一个 GUI,以便调用最后一个 .dll(称为 Generator)。我这样做是因为我想在其他项目中使用我的控件,并且我不想像 char *
.
所以这是我的问题:有时我可以按计划调用生成器函数。但是在一些调用之后,我得到一个 AccessViolationException。
我的生成器包含大量 C 函数和全局 C 变量。一切都正确标记为 extern "C"
。正如我所确定的,当我尝试使用全局变量时会发生违规。
我试图将所有全局变量放入生成器中的包装器-class,但我失败了,因为我无法将所有 C 类型转换为托管类型。
调用函数后,我 free(x)
正在 space 我的变量。在评论之前,我无法调用该函数两次以上。现在(注释掉之后)我可以调用 Generator 中的函数 4 次。总是。
我该如何解决这个问题?有没有办法像 "administrative rights" 那样提供我的函数,以允许他们使用全局变量做他们想做的事情?
提前感谢大家,我坚持了将近一个月,并且对如何编写 wrapper-classes 做了很多研究。
里昂
编辑:
这是我声明相关全局变量的方式:
"globals.h"
extern "C"{
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // fuer va_start, va_end
#include <string.h>
#include <malloc.h>
#include <windows.h>
//#include <omp.h>
// Used to prevent redefinition, _HAUPT_ is only defined in .dll-Header
#ifdef _HAUPT_
/*#define _HAUPT_*/
#define TYPE
int extreme = 0;
#else
#define TYPE extern
TYPE int extreme;
#endif
}
然而,当我在这里写我的编辑时,我发现问题出在我这边。我搞混了一个自己写的LinkedList
,当我试图用一个值声明一个未分配的指针时发生错误
对于这样的问题,您无法得到有用的答案。访问冲突是 C 代码失败的标准方式,在该语言中有许多方法可以调用未定义的行为。破坏内存的那种,这种破坏 最终 会使您的代码崩溃。代码失败的确切位置是 非常 很少接近有错误的语句。腐败产生影响可能需要一段时间。花一个星期或更长时间来查找错误一点也不稀奇。
基本方法:
- 编写运行 C 代码的单元测试,有助于缩小导致损坏的代码执行路径的数量。
- 确保在打开所有调试功能的情况下构建 C 代码,默认情况下为 MSVC 编译器中的调试构建启用。您需要从 /MDd 和 /RTC 获得的所有帮助。
- 使用 Application Verifier,一种可以检测堆损坏并向您显示导致损坏的语句的工具。最好用于失败的单元测试。
- 想想C语言是否真的对你完成工作有用。与托管代码相比,您可以从本机代码中挤出大约 25% 的额外性能,给予或索取,但如果您不能使其可靠地工作或失去一个月的生命,那么代价是相当高的。硬件比您的工时便宜很多。
我同意 Taus 的观点:
AccessViolationExceptions
are most often caused by accessing freed/unallocated memory or similar. Admin rights have nothing to do with it. A minimal example would go along way towards identifying the problem
封送拆收器通常会尝试创建该数据的托管 (C#) 表示,然后尝试 deallocate/free 非托管数据 (C++)。但是,您可能没有按照编组器期望的方式在 C/C++ 中分配内存,或者您可能不希望编组器尝试为您释放内存。
如果默认的解除分配行为与您的用例不匹配,那么您可以通过在 C# 代码中使用 IntPtr
手动处理 C++ 对象的解除分配(如果有的话)。例如,如果您从非托管代码返回字符串文字,则不应释放内存。请参阅此 post 示例。
如果您 post 显示您如何在非托管应用程序中分配内存、如何公开数据以及如何在 C# 应用程序中访问它的代码片段,我们可以帮助您查明问题。