P/Invoke C#struct,并将字符串连接到C void*
我在围绕第三方C库创建C#p/invoke包装时遇到问题。特别是,库中有一个带有签名的方法P/Invoke C#struct,并将字符串连接到C void*,c#,string,struct,pinvoke,void,C#,String,Struct,Pinvoke,Void,我在围绕第三方C库创建C#p/invoke包装时遇到问题。特别是,库中有一个带有签名的方法 int command(SomeHandle *handle, int commandNum, void *data, int datasize); 它是一个通配符方法,根据commandNum执行不同的操作。数据可以是指向任何对象的指针,如单个整数、字符[]或某种结构(我的问题) 我已声明包装如下: [DllImport("LIBRARY.DLL", EntryPoint = "command")]
int command(SomeHandle *handle, int commandNum, void *data, int datasize);
它是一个通配符方法,根据commandNum执行不同的操作。数据可以是指向任何对象的指针,如单个整数、字符[]或某种结构(我的问题)
我已声明包装如下:
[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, [In, Out] IntPtr Data, int DataSize);
现在,当我用一个操作码调用它来填充一个字节[]时,它会工作:
//WORKS, Buffer contains "library 1.0" after the call
const int BUFFER_SIZE = 128;
byte[] Buffer = new byte[BUFFER_SIZE];
int BytesWritten = 0;
GCHandle BufferHandle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
try
{
BytesWritten = Command(MyHandle, GET_VERSION, BufferHandle.AddrOfPinnedObject(), BUFFER_SIZE);
}
finally
{
BufferHandle.Free();
}
然而,当我用一个简单的结构尝试同样的方法时,我无法使它工作,无论我尝试了什么。结构如下所示:
public struct FormatInfoType
{
public int Format;
public IntPtr Name; //const char*
public IntPtr Extension; //const char*
}
FormatInfoType f = new FormatInfoType();
f.Format = 1;
f.Name = IntPtr.Zero;
f.Extension = IntPtr.Zero;
GCHandle fHandle = GCHandle.Alloc(f, GCHandleType.Pinned);
try
{
Command(MyHandle, GET_FORMAT_INFO, fHandle.AddrOfPinnedObject(), Marshal.SizeOf(f));
}
finally
{
fHandle.Free();
}
在这里,我应该用int(比如1)填充“Format”,然后调用“command(…)”将返回名称和扩展字段
如果我传递这个结构,代码将正确编译和运行,但结构中的值永远不会被修改。如果我将IntPtr更改为Strings或StringBuilders(并且我尝试了大量marshallas属性),那么我无法将IntPtr转换为struct,因为它变得不可blittable,并且GCHandle行抛出异常
在此方面的任何帮助都将不胜感激
编辑:
我尝试了许多方法来使用该结构调用command(),但目前看起来是这样的:
public struct FormatInfoType
{
public int Format;
public IntPtr Name; //const char*
public IntPtr Extension; //const char*
}
FormatInfoType f = new FormatInfoType();
f.Format = 1;
f.Name = IntPtr.Zero;
f.Extension = IntPtr.Zero;
GCHandle fHandle = GCHandle.Alloc(f, GCHandleType.Pinned);
try
{
Command(MyHandle, GET_FORMAT_INFO, fHandle.AddrOfPinnedObject(), Marshal.SizeOf(f));
}
finally
{
fHandle.Free();
}
您可以重载p/invoke签名,请尝试:
[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, ref FormatInfoType Data, int DataSize);
您能否显示将
FormatInfoType
封送到函数中的代码?您是否尝试过使用[MarshalAs(UnmanagedType.LPStr)]
属性标记的字符串?@Richard:我刚刚更新了问题@Ben,是的,我已经试过了,但是结构变得不可blittable,我无法得到一个IntPtr传递给命令(..)调用。我猜问题是我无法在托管代码中分配该结构中的字符串缓冲区,我必须依靠“command()”来完成,也许托管代码不喜欢这样。