指向本机 C++ 堆的指针上的 Marshal.PtrToStructure 是否正常?
Is Marshal.PtrToStructure on pointers that point to the native C++ heap sane?
我有一个使用 PInvoke 在 C# 和 C++ 之间封送数据的应用程序。该应用程序是一个本机 C++ 应用程序,它在内部使用 C# 部分启动 CLR。
有时我必须将数据从 C++ 编组到 C#,为此我使用 Marshal.PtrToStructure
。 C++部分基本上是这样的:
struct X {};
auto xPtr = new X; // somewhere in the application
callCSharp(xPtr); // somewhere else
C# 部分是这样的:
public void callCSharp(IntPtr xPtr)
{
var x = Marshal.PtrToStructure<X>(xPtr);
}
此代码可在我的 Windows 10 机器上运行,但我不确定是否 运行 使用此代码会遇到麻烦。生命周期管理全部在 C++ 中完成,因此我不必在 C# 端分配或释放任何东西。但是我不确定 CLR 是否总是可以访问本机堆。 xPtr
是使用 new
分配的,因此位于 C++ 应用程序的本机堆上。 Marshal.PtrToStructure<X>(xPtr)
然后尝试读取该位置的内存,但我不知道这是否会导致问题。
我读过 ,它表明 C++ 应用程序和 CLR 使用相同的堆(GetProcessHeap
即),所以这似乎支持我对 Windows 的发现10,但其他 OS 版本可能有所不同。
我的示例代码是否正常?这里有什么陷阱吗?此代码在 Windows 7、8 和 10 中有效吗?
是的,只要 C/C++ 代码不释放内存,这是完全合理和安全的。请注意,在这里使用 Marshal
并不总是必要的(或可取的);根据 <X>
是什么,您 也可以 以其他方式执行此操作,包括:
unsafe
(将 void*
转换为 X*
)
Unsafe.AsRef<X>(...)
(将 void*
转换为 ref X
)
new Span<X>(...)
(从 void*
创建一定数量的 X
的跨度;跨度就像一个向量,但与任意内存对话)
所有这些都是 zero-copy 方法,这意味着您的 C# 代码然后直接与完全相同的内存对话 space,而不是本地快照;但是如果你 取消引用 指针(托管或非托管)到 non-reference 本地,那么它会制作一个副本。
我有一个使用 PInvoke 在 C# 和 C++ 之间封送数据的应用程序。该应用程序是一个本机 C++ 应用程序,它在内部使用 C# 部分启动 CLR。
有时我必须将数据从 C++ 编组到 C#,为此我使用 Marshal.PtrToStructure
。 C++部分基本上是这样的:
struct X {};
auto xPtr = new X; // somewhere in the application
callCSharp(xPtr); // somewhere else
C# 部分是这样的:
public void callCSharp(IntPtr xPtr)
{
var x = Marshal.PtrToStructure<X>(xPtr);
}
此代码可在我的 Windows 10 机器上运行,但我不确定是否 运行 使用此代码会遇到麻烦。生命周期管理全部在 C++ 中完成,因此我不必在 C# 端分配或释放任何东西。但是我不确定 CLR 是否总是可以访问本机堆。 xPtr
是使用 new
分配的,因此位于 C++ 应用程序的本机堆上。 Marshal.PtrToStructure<X>(xPtr)
然后尝试读取该位置的内存,但我不知道这是否会导致问题。
我读过 GetProcessHeap
即),所以这似乎支持我对 Windows 的发现10,但其他 OS 版本可能有所不同。
我的示例代码是否正常?这里有什么陷阱吗?此代码在 Windows 7、8 和 10 中有效吗?
是的,只要 C/C++ 代码不释放内存,这是完全合理和安全的。请注意,在这里使用 Marshal
并不总是必要的(或可取的);根据 <X>
是什么,您 也可以 以其他方式执行此操作,包括:
unsafe
(将void*
转换为X*
)Unsafe.AsRef<X>(...)
(将void*
转换为ref X
)new Span<X>(...)
(从void*
创建一定数量的X
的跨度;跨度就像一个向量,但与任意内存对话)
所有这些都是 zero-copy 方法,这意味着您的 C# 代码然后直接与完全相同的内存对话 space,而不是本地快照;但是如果你 取消引用 指针(托管或非托管)到 non-reference 本地,那么它会制作一个副本。