4

我正在尝试学习如何围绕 DLL 编写包装器,但遇到了一些障碍。我有一个这样声明的结构:

[StructLayout(LayoutKind.Sequential)]
unsafe struct SDL_Surface
{
    public readonly UInt32 flags;             
    public readonly SDL_PixelFormat* format;  
    public readonly int w, h;                  
    public readonly int pitch;               
    public void* pixels;             

    /// <summary>Application data associated with the surface</summary>
    public void* userdata;           

    /// <summary>information needed for surfaces requiring locks</summary>
    public readonly int locked;              
    public readonly void* lock_data;           

    /// <summary>clipping information</summary>
    public readonly SDL_Rect clip_rect;        

    /// <summary>info for fast blit mapping to other surfaces</summary>
    private SDL_BlitMap *map;    // <--- Cannot take the address of, get the size of, or declare a pointer to a managed type 

    /// <summary>Reference count -- used when freeing surface</summary>
    public int refcount;             
}

当我尝试编译我的项目时,它给出了上述错误。

但是你会在上面注意到,我确实有一个指向另一个结构的指针。我试图弄清楚这两个结构之间的区别是什么使一个工作但另一个不工作,但我不确定;它们都是不安全的结构。它们如下:

[StructLayout(LayoutKind.Sequential)]
unsafe struct SDL_PixelFormat
{
    UInt32 format;
    SDL_Palette *palette;
    byte BitsPerPixel;
    byte BytesPerPixel;
    fixed byte padding [2];
    UInt32 Rmask;
    UInt32 Gmask;
    UInt32 Bmask;
    UInt32 Amask;
    byte Rloss;
    byte Gloss;
    byte Bloss;
    byte Aloss;
    byte Rshift;
    byte Gshift;
    byte Bshift;
    byte Ashift;
    int refcount;
    SDL_PixelFormat *next;
}

unsafe internal delegate int SDL_blit(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect);

[StructLayout(LayoutKind.Sequential)]
unsafe struct SDL_BlitMap
{
    SDL_Surface* dst;
    int identity;
    SDL_blit blit;
    void* data;
    SDL_BlitInfo info;

    /* the version count matches the destination; mismatch indicates
       an invalid mapping */
    UInt32 dst_palette_version;
    UInt32 src_palette_version;
}

[StructLayout(LayoutKind.Sequential)]
struct SDL_Rect
{
    int x, y;
    int w, h;
}

那么我必须改变什么才能使这个编译?


我相信这是导致问题的SDL_blit参考SDL_BlitMap。我已将其声明为代表;还有什么我应该声明的吗?它在 C 中被定义为:

typedef int (*SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
                         struct SDL_Surface * dst, SDL_Rect * dstrect);
4

2 回答 2

5

任何包含托管类型的结构都不能获取其地址。委托是一种引用类型,因此它们也是一种托管类型。这意味着 SDL_Blitmap 是托管类型,因为它包含对 SDL_blit 的托管引用,因此如果不先修复它就无法获得指向它的指针。

如果您尝试调用的函数已在 dll 中可用,我建议您查看 DllImportAttribute。( http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute( v=vs.100).aspx )

通过将公共静态 extern 声明与 DllImportAttribute 相结合,您可以调用在您正在互操作的 dll 中声明的任何全局函数。

或者,您需要创建一个 C/C++ 端函数,该函数接受一个函数指针并调用它,这可能会变得混乱。

于 2013-07-08T06:34:04.543 回答
2

如果你不依赖不安全的代码怎么办?如果您的代码对性能/速度至关重要,它可能会影响性能。类似这样的东西:

[StructLayout(LayoutKind.Sequential)]
struct SDL_PixelFormat
{
    UInt32 format;
    IntPtr palettePtr;
    byte BitsPerPixel;
    byte BytesPerPixel;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    byte padding[];
    UInt32 Rmask;
    UInt32 Gmask;
    UInt32 Bmask;
    UInt32 Amask;
    byte Rloss;
    byte Gloss;
    byte Bloss;
    byte Aloss;
    byte Rshift;
    byte Gshift;
    byte Bshift;
    byte Ashift;
    int refcount;
    IntPtr nextPtr;
}

[StructLayout(LayoutKind.Sequential)]
struct SDL_Surface
{
    public readonly UInt32 flags;
    public readonly IntPtr format;  
    public readonly int w, h;                  
    public readonly int pitch;               
    public IntPtr pixels;             

    /// <summary>Application data associated with the surface</summary>
    public IntPtr userdata;           

    /// <summary>information needed for surfaces requiring locks</summary>
    public readonly int locked;              
    public readonly IntPtr lock_data;           

    /// <summary>clipping information</summary>
    public readonly SDL_Rect clip_rect;        

    /// <summary>info for fast blit mapping to other surfaces</summary>
    private IntPtr mapPtr;

    /// <summary>Reference count -- used when freeing surface</summary>
    public int refcount;             
}

[StructLayout(LayoutKind.Sequential)]
struct SDL_BlitMap
{
    IntPtr dstPtr;
    int identity;
    SDL_blit blit;
    IntPtr data;
    SDL_BlitInfo info;

    /* the version count matches the destination; mismatch indicates
       an invalid mapping */
    UInt32 dst_palette_version;
    UInt32 src_palette_version;
}

[StructLayout(LayoutKind.Sequential)]
struct SDL_Rect
{
    int x, y;
    int w, h;
}

[UnmanagedFunctionPointer(CallingConvention.ToBeAdded)]
internal delegate int SDL_blit(ref SDL_Surface src, ref SDL_Rect srcrect, ref SDL_Surface dst, ref SDL_Rect dstrect);

当您需要读取任何结构指针时:

var palette = (SDL_Palette) Marshal.PtrToStructure(surface.palettePtr, typeof (SDL_Pallete));

否则,如果您希望坚持当前代码,请尝试将函数指针声明为 IntPtr 而不是委托,并在运行时使用 Marshal.GetDelegateForFunctionPointer 创建委托。

于 2013-07-08T14:44:52.503 回答