C# 使用带结构和指针的pinvoke
我试图在我的c代码中输入一个c函数。它接受一个struct和一个double作为输入,并返回一个相同类型的struct。我在c和c代码中定义了相同的结构。当PInvoke调用c函数时,我得到一个异常“方法类型签名与PInvoke不兼容”。有人能看出我做错了什么吗?谢谢 C: C#:C# 使用带结构和指针的pinvoke,c#,c,pinvoke,C#,C,Pinvoke,我试图在我的c代码中输入一个c函数。它接受一个struct和一个double作为输入,并返回一个相同类型的struct。我在c和c代码中定义了相同的结构。当PInvoke调用c函数时,我得到一个异常“方法类型签名与PInvoke不兼容”。有人能看出我做错了什么吗?谢谢 C: C#: 我知道这可能不是世界上最好的解决方案,但它在我的测试中对我有效,所以我将让你推断出你个人可能需要做的关于记忆释放的事情,并让你自己判断 我个人讨厌使用Marshal.Copy和Buffer.BlockCopy。我在这
我知道这可能不是世界上最好的解决方案,但它在我的测试中对我有效,所以我将让你推断出你个人可能需要做的关于记忆释放的事情,并让你自己判断 我个人讨厌使用Marshal.Copy和Buffer.BlockCopy。我在这里为此编写了自己的函数行:(特别是DTCSMemory项目->MemPtr结构),但为了便于移植,我使用标准函数对其进行了编程。我必须承认,我可能正在用字节做一些古怪的事情,但我只是在双重肯定(不是双关语) 如果结构物采用正常包装,则必须使用IntPtr.尺寸。通常情况下,一个简单的结构互操作可以解决这个问题,但我们这里不使用简单的结构互操作。如果结构是字节压缩的,那么您需要将其显示“IntPtr.Size”的位置改回“4” 也就是说,如果我们在C中有:
typedef struct myStruct_struct
{
int length;
double array[1];
}
myStruct;
__declspec(dllexport) myStruct *doSomething(const myStruct *inStruct, double val)
{
int i = sizeof(double);
//doSomething ...
myStruct *outStruct = (myStruct*)GlobalAlloc(0, sizeof(void*) + (8 * 256));
ZeroMemory(outStruct, sizeof(void*) + (8 * 256));
outStruct->length = 256;
outStruct->array[0] = inStruct->array[0] + val;
return outStruct;
}
那么C#中的代码就可以工作了:
public class Program
{
/// <summary>
/// myStruct is not marshaled, directly.
/// </summary>
public struct myStruct
{
public int Length;
public double[] Array;
private IntPtr _ptr;
/// <summary>
/// Custom marshal a structure in from interop (and optionally free the original pointer).
/// </summary>
/// <param name="ptr"></param>
/// <param name="freeOrig"></param>
/// <returns></returns>
public static myStruct MarshalIn(IntPtr ptr, bool freeOrig = true)
{
byte[] by = new byte[4];
myStruct ns = new myStruct();
Marshal.Copy(ptr, by, 0, 4);
ns.Length = BitConverter.ToInt32(by, 0);
ns.Array = new double[ns.Length];
by = new byte[ns.Length * 8];
Marshal.Copy(ptr + IntPtr.Size, by, 0, by.Length);
Buffer.BlockCopy(by, 0, ns.Array, 0, by.Length);
if (freeOrig) Marshal.FreeHGlobal(ptr);
return ns;
}
/// <summary>
/// Custom marshal a structure for calling interop.
/// </summary>
/// <returns></returns>
public IntPtr MarshalOut()
{
IntPtr ptr;
int l = IntPtr.Size + (8 * Array.Length);
ptr = Marshal.AllocHGlobal(l);
byte[] by = BitConverter.GetBytes(Length);
Marshal.Copy(by, 0, ptr, 4);
by = new byte[Length * 8];
Buffer.BlockCopy(Array, 0, by, 0, by.Length);
Marshal.Copy(by, 0, ptr + IntPtr.Size, by.Length);
_ptr = ptr;
return ptr;
}
/// <summary>
/// Free any associated pointer with this structure created with MarshalOut().
/// </summary>
public void Free()
{
if (_ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_ptr);
_ptr = IntPtr.Zero;
}
}
}
[DllImport("mylib.dll", SetLastError = true, CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr doSomething(IntPtr inStruct, double val);
static void Main()
{
// let's do some math.
myStruct ms = new myStruct(), ms2;
ms.Array = new double[1];
ms.Length = 1;
ms.Array[0] = 424.444;
ms2 = myStruct.MarshalIn(doSomething(ms.MarshalOut(), 524.444));
// Free this after the call.
ms.Free();
}
}
公共类程序
{
///
///myStruct不是直接编组的。
///
公共结构myStruct
{
公共整数长度;
公共双[]数组;
私人IntPtr_ptr;
///
///从互操作中自定义封送结构(并可以选择释放原始指针)。
///
///
///
///
公共静态myStruct MarshalIn(IntPtr ptr,bool freeOrig=true)
{
byte[]by=新字节[4];
myStruct ns=新的myStruct();
封送员副本(ptr,by,0,4);
ns.Length=BitConverter.ToInt32(by,0);
ns.数组=新的双精度[ns.长度];
by=新字节[ns.Length*8];
封送处理副本(ptr+IntPtr.Size,by,0,by.Length);
块复制(按,0,ns.数组,0,按.长度);
if(自由党)自由党元帅(ptr);
返回ns;
}
///
///自定义封送处理用于调用互操作的结构。
///
///
公共IntPtr封送处理()
{
IntPtr-ptr;
intl=IntPtr.Size+(8*Array.Length);
ptr=编组分配全局(l);
byte[]by=BitConverter.GetBytes(长度);
封送员副本(由,0,ptr,4);
by=新字节[长度*8];
块复制(数组,0,by,0,by.Length);
封送处理副本(按,0,ptr+IntPtr.Size,按.长度);
_ptr=ptr;
返回ptr;
}
///
///释放与使用MarshalOut()创建的此结构关联的任何指针。
///
公众免费
{
如果(ptr!=IntPtr.Zero)
{
自由全球元帅(_ptr);
_ptr=IntPtr.Zero;
}
}
}
[DllImport(“mylib.dll”,SetLastError=true,CharSet=CharSet.None,CallingConvention=CallingConvention.Cdecl)]
公共静态外部IntPtr剂量测量(IntPtr指令,双val);
静态void Main()
{
//让我们做一些数学题。
myStruct ms=newmystruct(),ms2;
ms.数组=新的双精度[1];
ms.长度=1;
ms.Array[0]=424.444;
ms2=myStruct.MarshalIn(doSomething(ms.marshallout(),524.444));
//通话结束后,请将此免费。
弗里女士();
}
}
LPStruct和Struct是易变的生物。通常,封送拆收器会返回一个错误,但是这次没有发生,但是如果你到达那个点,可能会发生,因为那不是ref或out结构,它只是一个结构(即使它是通过指针传递的,我也不认为它符合LPStruct的条件。最好是在参数行的末尾添加一个true ref struct变量来接收输出结构,并简单地返回void或bool作为函数的返回值。)不幸的是,我无法更改c代码签名。它在其他地方使用。[Marshallas(UnmanagedType.ByValArray)]数组声明中缺少。请删除UnmanagedType.LPStruct。您必须对参数使用ref来匹配本机代码中的myStruct*。如果函数返回数组中的数据,则需要使用IntPtr手动封送处理。然后您需要用C编写一个可调用的包装器。我刚刚注意到…它看起来像数组占位符对于可变长度数组,如果我没有弄错的话。可变长度数组必须手动封送。封送它们并不容易。如果您需要的话,我实际上已经在代码中找到了这个问题的解决方案,但是根据我所说的,应该足以让您计算出来。结构的内存分配到了某个地方?您自己的最好的解决方案是在托管代码中分配内存,并让封送处理程序完成所有工作。这需要将动态大小的数组排除在任何结构之外。这很容易做到。而且它消除了对所有这些代码的需要。然后他已经被套住了。使用共享堆进行分配的几率非常接近于零。修复接口就是解决方案。@ben这些天都是一样的SMSDN说:@Davidheffernanw他应该做的可能是用C或C++/CLI编写一个包装器,如果这是一个选项的话。。。
typedef struct myStruct_struct
{
int length;
double array[1];
}
myStruct;
__declspec(dllexport) myStruct *doSomething(const myStruct *inStruct, double val)
{
int i = sizeof(double);
//doSomething ...
myStruct *outStruct = (myStruct*)GlobalAlloc(0, sizeof(void*) + (8 * 256));
ZeroMemory(outStruct, sizeof(void*) + (8 * 256));
outStruct->length = 256;
outStruct->array[0] = inStruct->array[0] + val;
return outStruct;
}
public class Program
{
/// <summary>
/// myStruct is not marshaled, directly.
/// </summary>
public struct myStruct
{
public int Length;
public double[] Array;
private IntPtr _ptr;
/// <summary>
/// Custom marshal a structure in from interop (and optionally free the original pointer).
/// </summary>
/// <param name="ptr"></param>
/// <param name="freeOrig"></param>
/// <returns></returns>
public static myStruct MarshalIn(IntPtr ptr, bool freeOrig = true)
{
byte[] by = new byte[4];
myStruct ns = new myStruct();
Marshal.Copy(ptr, by, 0, 4);
ns.Length = BitConverter.ToInt32(by, 0);
ns.Array = new double[ns.Length];
by = new byte[ns.Length * 8];
Marshal.Copy(ptr + IntPtr.Size, by, 0, by.Length);
Buffer.BlockCopy(by, 0, ns.Array, 0, by.Length);
if (freeOrig) Marshal.FreeHGlobal(ptr);
return ns;
}
/// <summary>
/// Custom marshal a structure for calling interop.
/// </summary>
/// <returns></returns>
public IntPtr MarshalOut()
{
IntPtr ptr;
int l = IntPtr.Size + (8 * Array.Length);
ptr = Marshal.AllocHGlobal(l);
byte[] by = BitConverter.GetBytes(Length);
Marshal.Copy(by, 0, ptr, 4);
by = new byte[Length * 8];
Buffer.BlockCopy(Array, 0, by, 0, by.Length);
Marshal.Copy(by, 0, ptr + IntPtr.Size, by.Length);
_ptr = ptr;
return ptr;
}
/// <summary>
/// Free any associated pointer with this structure created with MarshalOut().
/// </summary>
public void Free()
{
if (_ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_ptr);
_ptr = IntPtr.Zero;
}
}
}
[DllImport("mylib.dll", SetLastError = true, CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr doSomething(IntPtr inStruct, double val);
static void Main()
{
// let's do some math.
myStruct ms = new myStruct(), ms2;
ms.Array = new double[1];
ms.Length = 1;
ms.Array[0] = 424.444;
ms2 = myStruct.MarshalIn(doSomething(ms.MarshalOut(), 524.444));
// Free this after the call.
ms.Free();
}
}