为什么在我从 C# 代码调用导入的 C++ 函数时抛出 AccessViolationException?
Why is an AccessViolationException thrown when I call an imported C++ function from C# code?
我已经阅读了很多关于该主题的帖子,但我还没有找到解决我的问题的方法。
在我的 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
。对于 return 类型 HRESULT WINAPI
,我使用数据类型 UInt32
,据我所知,也不需要编组吗? (我也尝试使用其他数据类型作为参数和 return 值,但总是出现相同的异常)
对于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();
}
}
}
终于可以确定问题了
为了检查参数的数据类型和return值,我在dll上使用了反编译器Snowman。看起来 dll 只定义了接口,而实现在开发人员忘记首先发送的另一个 dll 文件中。
一旦第二个 .dll 文件存储在我的程序的运行时文件夹中,函数调用就会起作用。我还想提一下,调用在有和没有 [In]
参数属性的情况下都有效。
虽然我不知道抛出异常的确切原因AccessViolationException: Attempted to read or write protected memory...
(我认为另一个异常更适合这里),但我很高兴问题能够得到解决。
感谢 Ben Voigt 和 David Heffernan 的评论!
我已经阅读了很多关于该主题的帖子,但我还没有找到解决我的问题的方法。
在我的 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
。对于 return 类型 HRESULT WINAPI
,我使用数据类型 UInt32
,据我所知,也不需要编组吗? (我也尝试使用其他数据类型作为参数和 return 值,但总是出现相同的异常)
对于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();
}
}
}
终于可以确定问题了
为了检查参数的数据类型和return值,我在dll上使用了反编译器Snowman。看起来 dll 只定义了接口,而实现在开发人员忘记首先发送的另一个 dll 文件中。
一旦第二个 .dll 文件存储在我的程序的运行时文件夹中,函数调用就会起作用。我还想提一下,调用在有和没有 [In]
参数属性的情况下都有效。
虽然我不知道抛出异常的确切原因AccessViolationException: Attempted to read or write protected memory...
(我认为另一个异常更适合这里),但我很高兴问题能够得到解决。
感谢 Ben Voigt 和 David Heffernan 的评论!