1

我在围绕第三方 C 库创建 C# P/invoke 包装器时遇到问题。特别是,该库有一个带有签名的方法

int command(SomeHandle *handle, int commandNum, void *data, int datasize);

它是一种通配符方法,根据 commandNum 执行不同的操作。data 可以是指向任何东西的指针,例如单个整数、char[] 或某种结构(我的问题)。

我已将包装器声明如下:


[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* 
}

在这里,我应该用一个 int(比如 1)填充“格式”,然后调用“命令(...)”是为了给我返回名称和扩展字段

如果我通过这个结构,代码编译并正确运行,但结构中的值永远不会被修改。如果我将 IntPtr 更改为 Strings 或 StringBuilders(并且我尝试了无数 MarshalAs 属性),那么我无法将 IntPtr 获取到结构,因为它变得不可 blittable 并且 GCHandle 行引发异常。

对此的任何帮助将不胜感激。

编辑:

我已经尝试了很多方法来调用 command() 的结构,但目前它看起来像这样:


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();
}
4

1 回答 1

3

您可以重载 p/invoke 签名,尝试:

[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, ref FormatInfoType Data, int DataSize);
于 2010-09-22T22:14:28.000 回答