调用非托管 dll 时发生 AccessViolation
从 ac# 应用程序调用非托管 Dll 时,我收到 AccessViolationException
。奇怪的是,导出的函数没有参数,因此问题不在于数据的编组。该函数没有参数,只返回一个整数。另请注意,调用约定不是问题。具有相同零参数和整数返回值(但名称不同)的相同函数可以正常工作。考虑到排除了编组和调用约定,这样的调用可能导致此异常的其余候选原因是什么?
更新:dll 函数是正确的,因为如果通过普通链接从其他非托管代码调用,则它可以完美运行。
更新 2:一切都在 32 位上编译和运行。我尝试过Win XP SP2 和Vista。这是一个有趣的事实:在 Vista 系统上它就像一个魅力。 XP 上失败。
更新 3:我没有获得源代码,但我了解了这个 dll 的基本功能,所以我尝试用我自己的 dll 重现该问题。故事是这样的:原始的 dll 是 ei.lib(Erlang 的 C 接口库)的某种包装。它导出一些辅助函数。因此,为了重现该问题,我在 ei.lib 周围创建了一个包装器 dll,它仅导出一个函数,即“test()”。我这样做是为了不弄乱编组之类的事情。我只想测试初始化、连接和发送消息。因此,我的 dll 的这个 test() 函数只调用 ei_connect_init()
,然后调用 ei_connect()
,最后调用 ei_reg_send()
,参数硬编码在内部。问题是,如果我调用这个 dll 并使用另一个非托管代码中的 test() 函数,它就可以正常工作。消息已发送。但是当我通过 DllImport 从 C# 调用它时,它只能在 Vista 上运行。 XP 上不行。在 XP 上,它会失败并在 .net 层上出现 AccessViolationException。我试图追踪问题,我发现从我的 dll 内部,任何对 ei_connect() 的调用,或任何读取 erl_errno 的尝试(这些在 ei 中定义) .lib)在 XP 上运行并被托管代码调用时会导致尝试读取或写入受保护的内存,从而导致应用程序崩溃。它不可能是一件微不足道的事情,因为它可以在 Vista 上运行,并且在由非托管代码调用时也可以运行。
When calling an unmanaged Dll from a c# application I get an AccessViolationException
. The strange thing is that the exported function has no arguments, so the problem is not in the Marshalling of data. The function gets no argument and just returns an integer. Also note that calling convention is not an issue. An identical function with the same zero arguments and integer return value (but different name) works just fine. What are the remaining candidate reasons that such a call could cause this exception considering the fact that marshalling and calling convention is ruled out?
UPDATE: The dll function is correct because if called from other unmanaged code through plain linking, then it works perfectly.
UPDATE 2: Everything is compiled and run on 32 bit. I tried Win XP SP2 and Vista. Here is an interesting fact: On Vista Systems it works like a charm. On XP it fails.
UPDATE 3: I didnt get the source code but I learned what essentially this dll does, so i tried to reproduce the problem with my own dll. Here is the story: The original dll is some kind of a wrapper to ei.lib (Erlang's c interface library). It exports some helper funcs. So to reproduce the problem I have made a wrapper dll around ei.lib which exports only one function, namely "test()". I did that so I wouldnt mess with marshalling and stuff. I wanted just to test an initialization, connecting and sending a message. So this test() func of my dll just calls ei_connect_init()
, then ei_connect()
and finaly ei_reg_send()
, with arguments hardcoded inside. The problem is that if I call this dll and use the test() function from another unmanaged code, it works ok. Message is sent. But when I call it from c# through DllImport then it works only on Vista. Not on XP. On XP it fails with a AccessViolationException on the .net layer. I ve tried to trace down the problem and I see that from inside my dll, any call to ei_connect()
, or any attempt to read erl_errno
(these are defined in ei.lib) when running on XP and being called by managed code result in trying to read or write protected memory so the app crashes. It cant be something trivial since it works on Vista and it works when called by unmanaged code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,我想我知道问题所在:ei.lib 使用 TLS(线程本地存储)。在ei接口源代码的
ei_pthreads.c
文件中,有这样的片段:如果未定义
USE_DECLSPEC_THREAD
,那么在源文件的下部,将使用TLS Api。现在,从msdn我发现:
因此,由于我使用 erlang for windows 的预编译二进制发行版提供的 erl 接口库,我想知道他们在编译这些二进制文件时是否定义了 USE_DECLSPEC_THREAD 。如果不是,那么我就陷入了困境,我将尝试其他事情来完成我的工作。如果他们确实定义了它,那么我必须安装 cygwin 并重新编译源代码而不定义它。 (哎呀...)。
最终更新:确实这就是问题所在。我必须安装 cygwin 并再次编译 erl_interface 代码,而不定义
USE_DECLSPEC_TRHEAD
。重新编译时还有另一个小问题,需要进行一个微小的更改,以便在包含 winbase.h 之前定义_WIN32_WINNT
,因为在省略USE_DECLSPEC_THREAD
后,代码使用 SwitchToThread仅当定义了_WIN32_WINNT
并且其值大于 0x400 时,才会在 winbase.h 中定义该值。OK I think i know the problem: the ei.lib uses TLS (Thread Local Storage). In the file
ei_pthreads.c
of the ei interface source code there is this snippet:If
USE_DECLSPEC_THREAD
is not defined then, lower in the source file, TLS Api is used instead.Now, from msdn i found that:
So , since I use the erl interface libs provided with the precompiled binary distribution of erlang for windows, I wonder if they defined
USE_DECLSPEC_THREAD
when compiling those binaries. If not then I am in dead end and I will try something else to do my job with. If they did define it then I must install cygwin and recompile the sources without defining it. (Yikes...).FINAL UPDATE: Indeed this was the problem. I had to install cygwin and compile the erl_interface code again without defining
USE_DECLSPEC_TRHEAD
. Also there is another little catch when recompiling, a tiny change is needed so that definition of_WIN32_WINNT
happens before inclusion of winbase.h because after the omission ofUSE_DECLSPEC_THREAD
the code uses SwitchToThread which is defined in winbase.h only if_WIN32_WINNT
is defined and with a value greater than 0x400.当非托管代码导致内存访问冲突时,会发生此异常。检查非托管函数是否正确。如果您有非托管代码的源代码,您还可以 启用 调试器进入非托管代码并查看问题出在哪里。
This exception occurs when the unmanaged code causes a memory access violation. Check to see that the unmanaged function is correct. If you have the source for the unmanaged code you can also enable the debugger to step into the unmanaged code and see where the problem is.