当我从 C# 代码调用导入的 C++ 函数时,为啥会引发 AccessViolationException?
Posted
技术标签:
【中文标题】当我从 C# 代码调用导入的 C++ 函数时,为啥会引发 AccessViolationException?【英文标题】:Why is an AccessViolationException thrown when I call an imported C++ function from C# code?当我从 C# 代码调用导入的 C++ 函数时,为什么会引发 AccessViolationException? 【发布时间】:2020-03-16 16:32:05 【问题描述】:我已经阅读了许多关于该主题的主题,但我还没有找到解决问题的方法。
在我的 C# 代码中,我尝试使用 DllImport
调用 C++ 函数。不幸的是,我没有 C++ 代码,但头文件提供了有关函数的信息:
ABCD Initialize
(
IN FLOAT a
, IN DWORD b
);
ABCD也在头文件中定义:
#define EFGH extern "C"
...
#define ABCD EFGH __declspec(dllexport) HRESULT WINAPI
在 C# 代码中,我尝试像这样调用 Initialize 函数:
[DllImport("path.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern UInt32 Initialize([In] float a, [In] UInt32 b);
...
Initialize(50.0f, 0);
根据this site,不需要对数据类型float
进行编组,我可以使用UInt32
来代替DWORD
。对于返回类型HRESULT WINAPI
,我使用数据类型UInt32
,据我了解,也不需要编组? (我也尝试使用其他数据类型作为参数和返回值,但总是得到相同的异常)
对于 DllImport 属性,已经测试了CharSet
和CallingConventions
的许多可能性,但我没有成功。在声明函数时,我还尝试了这两种变体,有和没有参数的[In]
属性。
函数调用时,抛出异常:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
我在这里遗漏了什么吗?成功调用该函数的下一步是什么?
谢谢。
这是完整的 C# 代码。如前所述,我没有用于构建 .dll 文件的代码。我也不允许共享 dll。
using System;
using System.Runtime.InteropServices;
namespace MyNamespace
class Program
[DllImport("path.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern UInt32 Initialize([In] float a, [In] UInt32 b);
static void Main(string[] args)
Initialize(50.0f, 0); // <- throws System.AccessViolationException
Console.ReadLine();
【问题讨论】:
如此处所述,该代码是正确的。我敢打赌,当您从真实代码更改某些内容时,您转录了某些内容。提交minimal reproducible example。 感谢您的评论!不幸的是,我不允许共享 .dll 文件,因此我无法提供可重现的示例。 C# 代码已接近完成,命名空间由一个带有 Main 函数的类组成,该函数仅调用Initialize(50.0f, 0);
。
当然你可以分享一个可重现的例子。切掉任何敏感的东西。
@DavidHeffernan 我编辑了问题并添加了完整的 C# 代码。不幸的是,我没有用于构建 C++ dll 的代码。此外,我不允许共享 .dll 文件或其中的一部分。头文件的(我猜的)相关部分可以在问题中找到。不幸的是,我不允许发布完整的 .h 文件。希望有帮助。感谢您的宝贵时间。
@luk:我可以向您保证这里不需要[In]
,从而为您节省一些组合来尝试。这是 x86 或 x64 代码还是其他架构?有些人比其他人更关心调用约定。 WINAPI
应该像您的 p/invoke 已经指定的那样为您设置 stdcall。
【参考方案1】:
终于,我可以确定问题所在了。
为了检查参数的数据类型和返回值,我在dll上使用了反编译器Snowman。看起来 dll 只定义了接口,并且实现在另一个 dll 文件中,开发人员首先忘记发送了。
一旦第二个 .dll 文件存储在我的程序的运行时文件夹中,函数调用就起作用了。我还想提一下,无论有无 [In]
参数属性,该调用都适用。
虽然我不知道引发异常 AccessViolationException: Attempted to read or write protected memory...
的确切原因(我认为另一个异常可能更适合这里),但我很高兴这个问题可以得到解决。
感谢 Ben Voigt 和 David Heffernan 的 cmets!
【讨论】:
以上是关于当我从 C# 代码调用导入的 C++ 函数时,为啥会引发 AccessViolationException?的主要内容,如果未能解决你的问题,请参考以下文章
调试由 C# Visual Studio 2010 插件导入的 C++ dll
为啥当我调用 DataAdapter.Update() 时,此 C# 代码会生成语法错误?