2017-01-19 4 views
1

J'essaie de marshaler les structures suivantes de C++ à C# sur un programme Windows CE et compacter framework 2.0. J'ai beaucoup de difficultés avec le triage des cordes.Tableau de regroupement de structures de C++ à C# dans WinCE

Je possède ce C++ code:

#define Console_Parameters_MAX 50 

struct AllParameters { 
    Parameter Parameters[Console_Parameters_MAX]; 
} ; 

struct Parameter { 
    int Index; 
    int Id; 
    char Value[20]; 
}; 

extern "C" { 
    BOOL GetAllConsoleParameters(AllParameters *pItem); 
} 

et ce sont les C# code correspondant:

[StructLayout(LayoutKind.Sequential)] 
public struct AllParameters { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] 
    public Parameter[] Parameters 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct Parameter { 
    public int Index; 
    public int Id; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    public byte[] Value; 
} 

[DllImport("exemple.dll", SetLastError = true)] 
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.Struct)] ref AllParameters pItem); 

et voilà comment je l'invoquons:

AllParameters item = new AllParameters(); 
if (AppAPI.GetAllConsoleParameters(ref item)) { 
    var array = item.Parameters; 
} 

Quand j'appelle le GetAllConsoleParameters j'ai l'exception NotSupportedException. J'ai essayé plusieurs configurations mais sans succès.

Quelqu'un peut-il nous conseiller sur la façon de l'atteindre?

Merci à l'avance

+0

Quel est le message de l'éxéption? – cubrr

+0

Un sttring est une classe et n'est pas équivalent au tableau char. Les tableaux de caractères IN C++ sont terminés par '\ 0'. Donc, dans C#, utilisez un octet [] au lieu d'un tableau char. – jdweng

+1

Je n'ai pas utilisé C++ depuis longtemps, mais je suis assez sûr que 'char []' et 'string []' ne sont pas équivalents. Je pense que vous voudrez peut-être juste une chaîne dans votre code C#. – Sean

Répondre

0

Follo aile ma solution, C++ code:

/* - not used 
#define Console_Parameters_MAX 50 

struct AllParameters { 
    Parameter Parameters[Console_Parameters_MAX]; 
} ; 
*/ 

struct Parameter { 
    int Index; 
    int Id; 
    char Value[20]; 
}; 

extern "C" { 
    BOOL GetAllConsoleParameters(Parameter pItem[], int size); 
} 

et C# code correspondant:

/* - not used 
[StructLayout(LayoutKind.Sequential)] 
public struct AllParameters { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] 
    public Parameter[] Parameters 
} 
*/ 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct Parameter { 
    public int Index; 
    public int Id; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] 
    public byte[] Value; 
} 

[DllImport("exemple.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] ConsoleParameter[] myStruct, int size); 

et le code Invoke:

ConsoleParameter[] item = new ConsoleParameter[50]; 
if (AppAPI.GetAllConsoleParameters(item, 50)) { 
    var array = item; 
} 

merci beaucoup pour l'aide

0

Cela fonctionne pour moi sur un bureau Windows. Vous pourriez avoir à modifier la convention d'appel à CDECL dans la DLL C et l'attribut C# DllImport, parce que je lis ici que CDECL est standard sur Windows CE: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx

Code C:

extern "C" { 
    __declspec(dllexport) BOOL __stdcall GetAllConsoleParameters(AllParameters *pItem) 
    { 
    pItem->Parameters[0].Index = 0; 
    pItem->Parameters[0].Id = 42; 
    CopyMemory(&pItem->Parameters[0].Value[0], "Hello World", 12); 
    pItem->Parameters[1].Index = 1; 
    pItem->Parameters[1].Id = 43; 
    CopyMemory(&pItem->Parameters[1].Value[0], "Hello World 43", 15); 
    return TRUE; 
    } 
} 

code C#:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
struct Parameter 
{ 
    int Index; 
    int Id; 
    //char Value[20]; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 
    string Value; 
}; 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
struct AllParameters 
{ 
    //Parameter Parameters[Console_Parameters_MAX]; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] 
    Parameter[] Parameters; 
}; 

class Program 
{ 
    [DllImport("MarshalC.dll", CallingConvention = CallingConvention.StdCall)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetAllConsoleParameters(ref AllParameters pItem); 

    static void Main(string[] args) 
    { 
     var size = Marshal.SizeOf<AllParameters>(); 
     AllParameters all = new AllParameters(); 
     bool result = GetAllConsoleParameters(ref all); 
    } 
} 
+0

travailler avec le cadre compact 2.0. Charset.Ansi pas implémenté – mircoso

+0

J'essaie le "C: \ Program Files (x86) \ Microsoft.NET \ SDK \ CompactFramework \ v2.0 \ WindowsCE \ mscorlib.dll" et dans cette bibliothèque ne contient pas Cdecl. Peut-être que ma librairie est dépassée? – mircoso

0

je le ferais comme ça

 [StructLayout(LayoutKind.Sequential)] 
     public struct AllParameters { 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] 
      public Parameter[] Parameters; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct Parameter { 
      public int Index; 
      public int Id; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] 
      public byte[] Value; 
     } 

     [DllImport("exemple.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] 
     public static extern bool GetAllConsoleParameters(ref IntPtr pItem); 


     static void Main(string[] args) 
     { 
      AllParameters allParameters = new AllParameters(); 
      allParameters.Parameters = new Parameter[50]; 
      IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(allParameters)); 

      int z = Marshal.SizeOf(allParameters); 

      if (GetAllConsoleParameters(ref ptr)) 
      { 
       Marshal.PtrToStructure(ptr, allParameters); 
       Parameter[] parameters = allParameters.Parameters; 
      } 

     } 
+0

Je tente votre solution mais rejette une exception dans Marshal.SizeOf (allParameters) avec exception: NotsupportedException. l'enum CallingConvention contient un seul élément WinApi. (J'utilise Framework: Compact Framework 2.0 et VS 2008). ne comprends pas pourquoi .... – mircoso

+0

Assurez-vous d'utiliser le code et les structures les plus récents.Je recevais des erreurs similaires avec le code posté original et fait des changements. Le code affiché ne donne plus cette erreur. La valeur de 'z' est 1400 = 50 * 28 ce qui est correct. Ainsi, le code passe un LPTR ptr à un bloc de mémoire pré-alloué de 1400 octets dans l'espace mémoire non géré. – jdweng

+0

Vous pouvez essayer ceci: int z = Marshal.SizeOf (allParameters.GetType()); – jdweng