在带参数的函数上使用 PInvoke 时出现 AccessViolationException
AccessViolationException when using PInvoke on functions with parameters
我目前正在使用 PInvoke 在 C# 中从 C++ 调用一些非托管函数;具体来自 PhysX 3.3.3。我对 PInvoke 比较陌生,所以我从一些简单的方法开始。我可以轻松调用不带参数的函数,但调用带参数的函数时遇到问题。
从简单开始,我使用了一个传入布尔值的函数,发现布尔值是不可 blittable 的类型,因此必须对它们进行封送处理。但是,将布尔封送处理添加到 PInvoke 签名仍然无效。
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getReportAllocationNames@Foundation@shdfnd@physx@@UEBA_NXZ")]
public static extern bool GetAllocationNames();
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?setReportAllocationNames@Foundation@shdfnd@physx@@UEAAX_N@Z")]
public static extern void SetAllocationNames([MarshalAs(UnmanagedType.U1)]bool name);
当我调用 SetAllocationNames(true) 时,我得到一个 AccessViolationException。我也尝试过使用其他成员名称作为 UnmanagedType 枚举(例如 U1、Bool),但无济于事。
我在调用函数之前加载 DLL,我使用正确的错位名称作为入口点,并且调用与此函数关联的所有参数(在本例中只有一个)。还有什么我想念的吗?
好的,我想我现在明白了。经过进一步研究,似乎继承函数对于 PInvoke 来说确实是有问题的。许多来源建议将 C++ 代码扁平化为 C 风格的界面。我将不得不改用 C++/CLI 项目。谢谢!
不幸的是,如果它们是用不同的编译器编译的(更糟糕的是,同一编译器的不同版本),则几乎不可能与其他 C++ 应用程序共享 C++ 库,却独自使用 PInvoke
.
其次,您还没有完全解决这个问题。 C++ 对方法(属于 class 的函数)的调用约定(在 x86 中)是 thiscall,这意味着 this
(调用方法的 class)是通过 ecx
或 rcx
寄存器传递。 cdecl
没有通过。其次,您甚至没有定义适当的 classes...
你应该做的是写一个C++包装器
编写函数,而不是方法(即 - 不绑定到任何 class 或结构),做任何你需要做的事情,并确保你知道他们的调用约定(让它成为常规的,例如 cdecl
或 fastcall
)。这样你就可以编写 C/C++ 代码来为你完成工作,并用 PInvoke
.
编写 C#
我目前正在使用 PInvoke 在 C# 中从 C++ 调用一些非托管函数;具体来自 PhysX 3.3.3。我对 PInvoke 比较陌生,所以我从一些简单的方法开始。我可以轻松调用不带参数的函数,但调用带参数的函数时遇到问题。
从简单开始,我使用了一个传入布尔值的函数,发现布尔值是不可 blittable 的类型,因此必须对它们进行封送处理。但是,将布尔封送处理添加到 PInvoke 签名仍然无效。
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getReportAllocationNames@Foundation@shdfnd@physx@@UEBA_NXZ")]
public static extern bool GetAllocationNames();
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?setReportAllocationNames@Foundation@shdfnd@physx@@UEAAX_N@Z")]
public static extern void SetAllocationNames([MarshalAs(UnmanagedType.U1)]bool name);
当我调用 SetAllocationNames(true) 时,我得到一个 AccessViolationException。我也尝试过使用其他成员名称作为 UnmanagedType 枚举(例如 U1、Bool),但无济于事。
我在调用函数之前加载 DLL,我使用正确的错位名称作为入口点,并且调用与此函数关联的所有参数(在本例中只有一个)。还有什么我想念的吗?
好的,我想我现在明白了。经过进一步研究,似乎继承函数对于 PInvoke 来说确实是有问题的。许多来源建议将 C++ 代码扁平化为 C 风格的界面。我将不得不改用 C++/CLI 项目。谢谢!
不幸的是,如果它们是用不同的编译器编译的(更糟糕的是,同一编译器的不同版本),则几乎不可能与其他 C++ 应用程序共享 C++ 库,却独自使用 PInvoke
.
其次,您还没有完全解决这个问题。 C++ 对方法(属于 class 的函数)的调用约定(在 x86 中)是 thiscall,这意味着 this
(调用方法的 class)是通过 ecx
或 rcx
寄存器传递。 cdecl
没有通过。其次,您甚至没有定义适当的 classes...
你应该做的是写一个C++包装器
编写函数,而不是方法(即 - 不绑定到任何 class 或结构),做任何你需要做的事情,并确保你知道他们的调用约定(让它成为常规的,例如 cdecl
或 fastcall
)。这样你就可以编写 C/C++ 代码来为你完成工作,并用 PInvoke
.
C#