Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 调用非托管dll时发生访问冲突_C#_Interop_Erlang_Unmanaged_Erl Interface - Fatal编程技术网

C# 调用非托管dll时发生访问冲突

C# 调用非托管dll时发生访问冲突,c#,interop,erlang,unmanaged,erl-interface,C#,Interop,Erlang,Unmanaged,Erl Interface,当从c应用程序调用非托管Dll时,我得到一个AccessViolationException。奇怪的是,导出的函数没有参数,所以问题不在于数据的编组。该函数不获取参数,只返回一个整数。还要注意,调用约定不是一个问题。具有相同零参数和整数返回值(但名称不同)的相同函数可以正常工作。考虑到编组和调用约定已被排除,此类调用可能导致此异常的其余候选原因是什么 更新:dll函数是正确的,因为如果通过普通链接从其他非托管代码调用,则它可以正常工作 更新2:所有内容都在32位上编译和运行。我试着赢XP SP2

当从c应用程序调用非托管Dll时,我得到一个
AccessViolationException
。奇怪的是,导出的函数没有参数,所以问题不在于数据的编组。该函数不获取参数,只返回一个整数。还要注意,调用约定不是一个问题。具有相同零参数和整数返回值(但名称不同)的相同函数可以正常工作。考虑到编组和调用约定已被排除,此类调用可能导致此异常的其余候选原因是什么

更新:dll函数是正确的,因为如果通过普通链接从其他非托管代码调用,则它可以正常工作

更新2:所有内容都在32位上编译和运行。我试着赢XP SP2和Vista。这里有一个有趣的事实:在Vista系统上,它就像一个魅力。在XP上它失败了


更新3:我没有得到源代码,但我了解了这个dll的基本功能,所以我尝试用自己的dll重现这个问题。故事是这样的:原始dll是ei.lib(Erlang的c接口库)的某种包装器。它导出一些辅助函数。为了重现这个问题,我在ei.lib周围创建了一个包装dll,它只导出一个函数,即“test()”。我这样做是为了不搞编组之类的事。我只想测试初始化,连接并发送消息。因此,我的dll的test()函数只调用
ei\u connect\u init()
,然后调用
ei\u connect()
,最后调用
ei\u reg\u send()
,并在其中硬编码参数。问题是,如果我调用这个dll并从另一个非托管代码中使用test()函数,它工作正常。消息已发送。但当我从c#通过DllImport调用它时,它只在Vista上工作。不是在XP上。在XP上,它失败,在.net层上出现AccessViolationException。我试图找出问题所在,我发现在我的dll中,当在XP上运行并被托管代码调用时,任何对
ei_connect()
的调用,或任何试图读取
erl_errno
(这些在ei.lib中定义)的尝试都会导致尝试读取或写入受保护的内存,因此应用程序崩溃。它不可能是微不足道的,因为它可以在Vista上工作,并且在被非托管代码调用时也可以工作

当非托管代码导致内存访问冲突时,会发生此异常。检查非托管函数是否正确。如果您有非托管代码的源代码,还可以使用调试器进入非托管代码并查看问题所在。

好的,我想我知道问题所在:ei.lib使用TLS(线程本地存储)。在ei接口源代码的文件
ei_pthreads.c
中有以下代码段:

#ifdef __WIN32__
#ifdef USE_DECLSPEC_THREAD
/* Define (and initialize) the variable __erl_errno */
volatile __declspec(thread) int __erl_errno = 0;
#else
static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES;
static LONG volatile tls_init_mutex = 0;
#endif
#endif
如果未定义
USE\u DECLSPEC\u THREAD
,则在源文件的下方使用TLS Api。 现在,我从msdn中发现:

在以前的Windows操作系统上 Windows Vista,
\u declspec(线程)
有一些局限性。如果一个DLL 声明任何非本地数据或对象 由于
\u declspec(线程)
,它可能导致 如果是动态的,则为保护故障 加载。在用 LoadLibrary,它会导致系统故障 每当代码引用 非本地
\u declspec(线程)
数据。 因为全局变量空间 在运行时分配一个线程 此空间的大小基于 计算项目的需求 应用程序加上 所有静态加载的DLL 链接。当您使用LoadLibrary时 无法扩展此空间以允许 声明的线程局部变量 使用
\u declspec(螺纹)
。使用TLS DLL中的API,如TlsAlloc,用于 如果DLL可能是空的,请分配TLS 加载了LoadLibrary

因此,由于我使用了预编译的erlang for windows二进制发行版提供的erl接口库,我想知道它们在编译这些二进制文件时是否定义了
use\u DECLSPEC\u THREAD
。如果没有,那么我就死定了,我会尝试其他方法来完成我的工作。如果他们确实定义了它,那么我必须安装cygwin并在不定义它的情况下重新编译源代码。(哎呀…)


最后更新:事实上这就是问题所在。我必须安装cygwin并重新编译erl_接口代码,而不必定义
USE_DECLSPEC\u TRHEAD
。在重新编译时还有一个小问题,需要进行微小的更改,以便在包含winbase.h之前定义
\u WIN32\u WINNT
,因为在省略
使用DECLSPEC\u THREAD
之后,仅当定义了
\u WIN32\u WINNT
且值大于0x400时,代码才使用winbase.h中定义的SwitchToThread

此外,我没有访问源代码的权限,我将尝试获取至少包含调试信息的对象,并尝试调试程序。非托管库是否具有某种静态初始化函数,在使用前应调用该函数?还要确保没有32 64位不匹配。如果非托管代码为32位且托管代码以64位运行,则可能也会出现此异常。我在c#中使用了非托管dll,方法与非托管测试应用程序调用的方法相同。1调用有问题的函数。c#调用如何以不同于非托管测试应用程序调用的方式影响静态初始化?有些库要求您在使用前调用静态init函数,听起来您的函数没有。你调查过另一个建议了吗?在过去,当托管程序集以等于AnyCPU的平台目标构建,然后在64位操作系统上运行时,调用非托管32位代码时,我遇到过一些问题。