在C中作为参数传递结构指针# 我有一个C++函数,我导出到一个DLL中。我包含一个结构指针作为参数之一。我需要在C#中使用此函数,因此我使用DLLImport作为函数,并使用StructLayout在C#中重新创建了结构。我尝试了使用ref传入参数,也尝试了使用marshallas(UnmangedType.Struct)和Marshal.PtrToStructure封送参数。参数的传递仍然不正确
例如:在C中作为参数传递结构指针# 我有一个C++函数,我导出到一个DLL中。我包含一个结构指针作为参数之一。我需要在C#中使用此函数,因此我使用DLLImport作为函数,并使用StructLayout在C#中重新创建了结构。我尝试了使用ref传入参数,也尝试了使用marshallas(UnmangedType.Struct)和Marshal.PtrToStructure封送参数。参数的传递仍然不正确,c#,struct,pointers,marshalling,C#,Struct,Pointers,Marshalling,例如: [DllImport("testdll.dll")] public static extern int getProduct(int num1, int num2, [MarshalAs(UnmanagedType.Struct)] ref test_packet tester); 还有一点信息,这个结构包含一个byte*var,我认为这可能会导致将参数作为ref传递的问题。有什么想法吗?我走对了吗?谢谢你的帮助 感谢nobugz的回复。以下是struct def的示例: //C# D
[DllImport("testdll.dll")]
public static extern int getProduct(int num1, int num2, [MarshalAs(UnmanagedType.Struct)] ref test_packet tester);
还有一点信息,这个结构包含一个byte*var,我认为这可能会导致将参数作为ref传递的问题。有什么想法吗?我走对了吗?谢谢你的帮助
感谢nobugz的回复。以下是struct def的示例:
//C# DEFINITION
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct test_packet
{
public UInt32 var_alloc_size;
public byte* var;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_TAG_LENGTH)]
public byte[] tag;
}
//ORIGINAL UNMANAGED STRUCT
typedef struct test_packet_tag
{
unsigned int var_alloc_size;
unsigned char *var;
unsigned char tag[MAX_TAG_LENGTH];
} test_packet;
使用“ref”是正确的方法,去掉[Marshallas]属性。真正的问题几乎可以肯定是结构声明。你没有发布任何有助于我们的信息
DllImportAttribute.CharSet属性错误,请将其设为CharSet.Ansi。“var”成员声明错误,请将其设为字节[]。请确保在调用之前对其进行初始化:
var product = new test_packet();
product.var_alloc_size = 666; // Adjust as needed
product.var = new byte[product.var_alloc_size];
int retval = getProduct(42, 43, ref product);
最好的猜测是,希望它能起作用。您最初的p/Invoke声明应该可以,尽管您根本不需要
UnmanagedType.Struct
。问题似乎出在C#struct声明上。特别是,为什么字段声明的顺序与C++版本不同? 这是我个人的一个例子。这可能真的很复杂。请注意,将数组作为指针移动并不容易,因此您应该看看如何在c#端实现这一点。这应该会影响很多主要的数据类型。您必须确保元素完全对齐。否则,它看起来会正常工作,但您将得到糟糕的PTR(最多)。我在移动这个结构时遇到了很多麻烦,这是唯一有效的方法。祝你好运
功能信号
[DllImport("stochfitdll.dll", EntryPoint = "Init", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void Init([MarshalAs(UnmanagedType.LPStruct)] ModelSettings settings);
C++端
#pragma pack(push, 8)
struct ReflSettings
{
LPCWSTR Directory;
double* Q;
double* Refl;
double* ReflError;
double* QError;
int QPoints;
double SubSLD;
double FilmSLD;
double SupSLD;
int Boxes;
double FilmAbs;
double SubAbs;
double SupAbs;
double Wavelength;
BOOL UseSurfAbs;
double Leftoffset;
double QErr;
BOOL Forcenorm;
double Forcesig;
BOOL Debug;
BOOL XRonly;
int Resolution;
double Totallength;
double FilmLength;
BOOL Impnorm;
int Objectivefunction;
double Paramtemp;
LPCWSTR Title;
};
#pragma pack(pop)
C侧-
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]公共结构测试数据包{public byte*var;[Marshallas(UnmanagedType.ByValArray,SizeConst=MAX_TAG_LENGTH)]公共字节[]标记;公共UInt32 var_alloc_size;//在C}中是无符号int。把它放在你的问题里。还要发布它的非托管声明。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
public class ModelSettings:IDisposable
{
#region Variables
public string Directory;
public IntPtr Q;
public IntPtr Refl;
public IntPtr ReflError;
public IntPtr QError;
public int QPoints;
public double SubSLD;
public double SurflayerSLD;
public double SupSLD;
public int Boxes;
public double SurflayerAbs;
public double SubAbs;
public double SupAbs;
public double Wavelength;
public bool UseAbs;
public double SupOffset;
public double Percerror;
public bool Forcenorm;
public double Forcesig;
public bool Debug;
public bool ForceXR;
public int Resolution;
public double Totallength;
public double Surflayerlength;
public bool ImpNorm;
public int FitFunc;
public double ParamTemp;
public string version = "0.0.0";
[XmlIgnoreAttribute] private bool disposed = false;
#endregion
public ModelSettings()
{ }
~ModelSettings()
{
Dispose(false);
}
#region Public Methods
public void SetArrays(double[] iQ, double[] iR, double[] iRerr, double[] iQerr)
{
//Blank our arrays if they hold data
if (Q == IntPtr.Zero)
ReleaseMemory();
int size = Marshal.SizeOf(iQ[0]) * iQ.Length;
try
{
QPoints = iQ.Length;
Q = Marshal.AllocHGlobal(size);
Refl = Marshal.AllocHGlobal(size);
ReflError = Marshal.AllocHGlobal(size);
if (iQerr != null)
QError = Marshal.AllocHGlobal(size);
else
QError = IntPtr.Zero;
Marshal.Copy(iQ, 0, Q, iQ.Length);
Marshal.Copy(iR, 0, Refl, iR.Length);
Marshal.Copy(iRerr, 0, ReflError, iRerr.Length);
if (iQerr != null)
Marshal.Copy(iQerr, 0, QError, iQerr.Length);
}
catch (Exception ex)
{
//error handling
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
ReleaseMemory();
// Note disposing has been done.
disposed = true;
}
}
private void ReleaseMemory()
{
if (Q != IntPtr.Zero)
{
Marshal.FreeHGlobal(Q);
Marshal.FreeHGlobal(Refl);
Marshal.FreeHGlobal(ReflError);
if (QError != IntPtr.Zero)
Marshal.FreeHGlobal(QError);
}
}
#endregion
}