如何将IntPtr获取到结构?

时间:2013-07-10 02:49:38

标签: c# interop

我有一个带签名的方法

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转换为IntPtr 的速度大约相同,为IntPtr生成Rect,这让我怀疑当你使用refs时,C#正在做一些非常相似的事情。一旦我将它设为Rect?并将条件逻辑添加到方法中,它运行速度就会慢50%......因此4重载路径可能是最快的。然而,我们谈论100K迭代100-150ms,这意味着该方法本身是超级便宜的,这可能是条件具有如此显着影响的原因。因此,我坚持使用我的自定义StructToPtr解决方案,因为这是最简单的解决方案。

2 个答案:

答案 0 :(得分:6)

您想使用Marshal.StructureToPtr

您还必须为结构分配和释放内存。

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

找到

答案 1 :(得分:-2)

这里有我所拥有的,我使用的是来自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 ="这是一个字符串&#34 ;;