我正在尝试学习如何围绕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);
答案 0 :(得分: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 ++端函数,它接受一个函数指针并调用它,这可能会变得混乱。
答案 1 :(得分: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创建委托。