简体   繁体   English

将结构指针作为参数传递给C#

[英]Passing a struct pointer as a parameter in C#

I have a function in C++ that I exported to a DLL. 我有一个C ++函数,我导出到DLL。 I contains a struct pointer as one of the parameters. 我包含一个struct指针作为参数之一。 I need to use this function in C#, so I used DLLImport for the function and recreated the struct in C# using StructLayout. 我需要在C#中使用这个函数,所以我使用DLLImport作为函数,并使用StructLayout在C#中重新创建了struct。 I've tried passing in the parameter using ref as well as tried Marshaling it in using MarshalAs(UnmangedType.Struct) and Marshal.PtrToStructure. 我尝试使用ref传递参数,并尝试使用MarshalAs(UnmangedType.Struct)和Marshal.PtrToStructure进行Marshaling。 The parameter still isn't passing correctly. 参数仍未正确传递。

Example: 例:

[DllImport("testdll.dll")]
public static extern int getProduct(int num1, int num2, [MarshalAs(UnmanagedType.Struct)] ref test_packet tester);

One more tidbit of info, the struct contains a byte* var, which I think may be causing the problem in terms of passing the param as ref. 还有一小段信息,结构包含一个字节* var,我认为这可能导致将param作为ref传递的问题。 Any ideas? 有任何想法吗? Am I on the right track? 我是在正确的轨道上吗? Thanks for the help. 谢谢您的帮助。

Thanks nobugz for the response. 感谢nobugz的回复。 Here's a sample of the struct def: 这是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;

Using "ref" is the correct way, get rid of the [MarshalAs] attribute. 使用“ref”是正确的方法,摆脱[MarshalAs]属性。 The real problem is almost certainly the structure declaration. 真正的问题几乎可以肯定是结构宣言。 You didn't post anything that would help us help you with that. 你没有发布任何可以帮助我们帮助你的东西。


The DllImportAttribute.CharSet property is wrong, make it CharSet.Ansi. DllImportAttribute.CharSet属性是错误的,使它成为CharSet.Ansi。 The "var" member is declared wrong, make it byte[]. “var”成员声明错误,使其成为byte []。 Be sure to initialize it before the call: 请务必在通话前初始化它:

 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);

Best guess, hope it works. 最好的猜测,希望它有效。

Here's an example from my personal stuff. 这是我个人的一个例子。 It can be really complicated. 它可能非常复杂。 Note that its not easy to move arrays over as pointers, so you should look at how one does that in the c# side. 请注意,将数组作为指针移动并不容易,因此您应该看看如何在c#端执行此操作。 This should hit a lot of the major data types. 这应该会涉及很多主要的数据类型。 You must make sure your elements line up EXACTLY. 您必须确保您的元素完全排列。 Otherwise it will look like its working, but you'll get bad ptrs (at best). 否则它会看起来像它的工作,但你会得到糟糕的ptrs(充其量)。 I had a great deal of trouble when moving this struct, and this was the only approach that worked. 移动这个结构时我遇到了很多麻烦,这是唯一有效的方法。 Good luck 祝好运

Function sig - 功能信号 -

  [DllImport("stochfitdll.dll", EntryPoint = "Init", ExactSpelling = false,  CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    public static extern void Init([MarshalAs(UnmanagedType.LPStruct)] ModelSettings settings);

C++ side 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# side - C#侧 -

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

Your original P/Invoke declaration should be okay, though you shouldn't need UnmanagedType.Struct there at all. 你的原始P / Invoke声明应该没问题,尽管你根本不需要UnmanagedType.Struct The problem seems to be with your C# struct declaration. 问题似乎与您的C#结构声明有关。 In particular, why is the order of the field declarations different from the C++ version? 特别是,为什么字段声明的顺序与C ++版本不同?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM