2010-02-19 8 views
3

J'ai une fonction en C++ que j'ai exportée vers une DLL. I contient un pointeur struct comme l'un des paramètres. J'ai besoin d'utiliser cette fonction en C#, j'ai donc utilisé DLLImport pour la fonction et recréé la structure en C# en utilisant StructLayout. J'ai essayé de passer dans le paramètre using ref aussi bien que essayé Marshaling en utilisant MarshalAs (UnmangedType.Struct) et Marshal.PtrToStructure. Le paramètre ne passe toujours pas correctement.Passage d'un pointeur struct en tant que paramètre dans C#

Exemple:

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

Encore une friandise d'information, le struct contient un octet * var, qui je pense peut être la cause du problème en termes de passer le param ref. Des idées? Suis-je sur la bonne voie? Merci pour l'aide.

Merci à nobugz pour la réponse. Voici un exemple de la structure 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; 

Répondre

4

L'utilisation de "ref" est la bonne façon de se débarrasser de l'attribut [MarshalAs]. Le vrai problème est presque certainement la déclaration de structure. Vous n'avez rien posté qui pourrait nous aider à vous aider avec cela.


La propriété DllImportAttribute.CharSet est faux, faire CharSet.Ansi. Le membre "var" est déclaré faux, faites-le byte []. Assurez-vous de l'initialiser avant l'appel:

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

Meilleure estimation, espérons que cela fonctionne.

+0

[StructLayout (LayoutKind.Sequential, charset = CharSet.Unicode)] public struct test_packet { \t octet public * var; \t [MarshalAs (UnmanagedType.ByValArray, SizeConst = MAX_TAG_LENGTH)] \t public octet [] tag; \t public UInt32 var_alloc_size; // était non signé int en C } –

+4

Oh Seigneur. Mettez-le dans votre question. Affichez également la déclaration non gérée de celui-ci. –

0

Votre déclaration P/Invoke d'origine devrait être correcte, même si vous ne devriez pas y avoir besoin de UnmanagedType.Struct. Le problème semble être avec votre déclaration de structure C#. En particulier, pourquoi l'ordre des déclarations de champ est-il différent de la version C++?

1

Voici un exemple de mes affaires personnelles. Cela peut être vraiment compliqué. Notez qu'il n'est pas facile de déplacer des tableaux sous la forme de pointeurs, donc vous devriez regarder comment on fait ça du côté C#. Cela devrait frapper beaucoup de types de données majeurs. Vous devez vous assurer que vos éléments sont alignés EXACTEMENT. Sinon, cela ressemblera à son fonctionnement, mais vous obtiendrez de mauvais ptrs (au mieux). J'ai eu beaucoup de mal à déplacer cette structure, et c'était la seule approche qui fonctionnait. Bonne chance

Fonction 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ôté 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# côté -

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