所以,这个问题已经出现了很多变种,在看了几个后我仍然无法弄明白.
这是C代码:
typedef struct
{
unsigned long Identifier;
char Name[128];
} Frame;
Frame GetFrame(int index);
Run Code Online (Sandbox Code Playgroud)
这是C#代码:
struct Frame
{
public ulong Identifier;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 128)]
public char[] Name;
}
[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern Frame GetFrame(int index);
Run Code Online (Sandbox Code Playgroud)
这是我在C#中尝试过的最后一次尝试,看起来非常符合逻辑,但我得到的错误是"方法的签名与PInvoke不兼容".所以,我有点迷失下一步的尝试.任何帮助表示赞赏.
谢谢,凯文
Kevin 更新了这个作为我的答案的编辑
我应该改变我的C代码:
void GetFrame(int index, Frame * f);
Run Code Online (Sandbox Code Playgroud)
并使用C#代替:
struct Frame
{
public uint Identifier;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)]
public string Name;
}
[DllImport("XNETDB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern void GetFrame(int index, ref Frame f);
Run Code Online (Sandbox Code Playgroud)
Jar*_*Par 21
您选择的PInvoke签名有两个问题.
第一个很容易解决.你有误译unsigned long.在C中,a unsigned long通常只有4个字节.您选择了long8个字节的C#类型.更改要使用的C#代码uint将解决此问题.
第二个有点困难.正如Tergiver指出的那样,CLR Marshaller只支持返回位置的结构,如果它是blittable的话.Blittable是一种奇特的方式,它说它在本机代码和托管代码中具有完全相同的内存表示.您选择的结构定义不是blittable,因为它有一个嵌套数组.
如果您记得PInvoke是一个非常简单的过程,这可以解决.CLR Marshaller真的只需要你用你的类型和pinvoke方法的签名回答2个问题
在这种情况下,字节数是sizeof(unsigned long) + 128 == 132.所以我们需要做的就是构建一个blittable的托管类型,其大小为132字节.最简单的方法是定义一个blob来处理数组部分
[StructLayout(LayoutKind.Sequential, Size = 128)]
struct Blob
{
// Intentionally left empty. It's just a blob
}
Run Code Online (Sandbox Code Playgroud)
这是一个没有成员的结构,对于编组来说,它的大小为128字节(作为奖励它是blittable!).现在我们可以轻松地将Frame结构定义为a uint和此类型的组合
struct Frame
{
public int Identifier;
public Blob NameBlob;
...
}
Run Code Online (Sandbox Code Playgroud)
现在我们有一个blittable类型,其大小为marshaller将看到132字节.这意味着它可以正常使用GetFrame您定义的签名
剩下的唯一部分是让您访问char[]名称的实际内容.这有点棘手,但可以通过一些元帅魔法来解决.
public string GetName()
{
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(128);
Marshal.StructureToPtr(NameBlob, ptr, false);
return Marshal.PtrToStringAnsi(ptr, 128);
}
finally
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我无法对调用约定部分发表评论,因为我不熟悉GetFrameAPI,但我肯定会检查它.
Ter*_*ver 10
问题是本机函数返回一个非blittable类型作为返回值.
http://msdn.microsoft.com/en-us/library/ef4c3t39.aspx
P/Invoke不能将非blittable类型作为返回值.
你不能p/Invoke该方法.[ 编辑 它实际上是可能的,请参阅JaredPar的答案 ]
按值返回132个字节是个坏主意.如果这个本机代码是你的,我会解决它.您可以通过分配132个字节并返回指针来修复它.然后添加一个FreeFrame方法来释放该内存.现在它可以是p/Invoked.
或者,您可以将其更改为接受指向它将填充的Frame内存的指针.
| 归档时间: |
|
| 查看次数: |
7706 次 |
| 最近记录: |