如何获取结构的IntPtr

本文关键字:结构 IntPtr 获取 何获取 | 更新日期: 2023-09-27 18:21:41

我有一个带有签名的方法

public int Copy(Texture texture, Rect? srcrect, Rect? dstrect)

Rect是一个结构,但我需要允许调用者也将null(或IntPtr.Zero)传递给该方法。

然后我想把它传递给一个带有签名的DLL

[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_RenderCopy")]
internal static extern int RenderCopy(IntPtr renderer, IntPtr texture, IntPtr srcrect, IntPtr dstrect);

我希望我能做以下事情:

return SDL.RenderCopy(_ptr, texture._ptr, srcrect.HasValue ? (IntPtr)srcrect.Value : IntPtr.Zero, dstrect.HasValue ? (IntPtr)dstrect.Value : IntPtr.Zero);

但我不能那样投射结构。有没有其他方法可以让我从中获得IntPtr


另一种选择是创建4个过载:

  • ref Rect, ref Rect
  • IntPtr, IntPtr
  • ref Rect, IntPtr
  • IntPtr, ref Rect

如果我需要传递2个以上的结构指针,这可能会变得更加混乱。


我想出了一个解决方案,但我对此有一些问题:

public int Copy(Texture texture, Rect? srcrect=null, Rect? dstrect=null)
{
    return SDL.RenderCopy(_ptr, texture._ptr, srcrect.HasValue ? StructToPtr(srcrect) : IntPtr.Zero, dstrect.HasValue ? StructToPtr(dstrect) : IntPtr.Zero);
}
private static IntPtr StructToPtr(object obj)
{
    var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
    Marshal.StructureToPtr(obj, ptr, false);
    return ptr;
}

如果我使用ref Rect,我就不必为结构分配内存了——这与现在有什么不同?


我做了一些实验。ref Rect解决方案的运行速度与

Rect转换为IntPtrRect生成IntPtr的速度大致相同,这让我怀疑当您使用refs时,C#在幕后做着非常类似的事情。一旦我把它变成Rect?并将条件逻辑添加到方法中,它的运行速度就会慢50%。。。因此4过载路线可能是最快的。然而,我们谈论的是100K迭代的100-150毫秒,这意味着该方法本身非常便宜,这可能就是为什么条件语句具有如此显著的影响。因此,我坚持使用我的自定义StructToPtr解决方案,因为它是最简单的解决方案。

如何获取结构的IntPtr

您想要使用Marshal.StructureToPtr

您还必须为结构分配和取消分配内存。

关于这个主题的好博客可以在http://www.developerfusion.com/article/84519/mastering-structs-in-c/

以下是我所拥有的,我使用的是m$DLL中的API,原型如下:

HRESULT C_API(LPCWSTR name, PSTRUCT_WHATEVER *ppStruct);

结构定义如下:

typedef struct whatever {
    LPCWSTR x;
    LPCWSTR y;
}

在C#中,我定义了以下内容:

[StructLayout(LayoutKind.Sequential)]
public class WHATEVER {
    public IntPtr x;
    public IntPtr y;
}
[DllImport("msdll.dll", SetLastError=false, CharSet=CharSet.Unicode)]
    public static extern long C_API(String name, out IntPtr ppStruct);

使用它:

IntPtr s;           
long HR = C_API("myname", out s);
WHATEVER pInfo = (WHATEVER) Marshal.PtrToStructure(s, typeof(WHATEVER));
String mystring = Marshal.PtrToStringAuto(pInfo.x);

此时mystring="这是一个字符串";