2017-01-19 17 views
1

Я пытаюсь маршалировать следующие структуры от C++ до C# в программе Windows CE и компактной структуре 2.0. У меня много трудностей с сортировкой строк.Маршаллинг массив структур от C++ до C# в WinCE

У меня есть этот C++ код:

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

и это есть соответствующий C# код:

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

и это, как я вызываю его:

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

Когда я звоню в GetAllConsoleParameters я получаю исключение NotSupportedException. Я пробовал много конфигураций, но без успеха.

Может ли кто-нибудь посоветовать, как его достичь?

Заранее спасибо

+0

Что такое послание исключение? – cubrr

+0

Строка sttring является классом и не эквивалентна массиву char. IN C++ символьные массивы заканчиваются на '\ 0'. Таким образом, в C# используйте байт [] вместо массива char. – jdweng

+1

Я не использовал C++ довольно долго, но я уверен, что 'char []' и 'string []' не эквивалентны. Я думаю, вам может понадобиться просто 'string' в вашем коде C#. – Sean

ответ

0

Follo крыло мое решение, C++ код:

/* - 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); 
} 

и соответствующий C# код:

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

и код Invoke:

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

Большое спасибо за помощь

0

Это работает для меня на рабочем столе Windows. Вы, возможно, придется изменить соглашение о вызовах для Cdecl в C DLL и атрибут C# DllImport, потому что я читал здесь, что Cdecl является стандартным Windows CE: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx

код 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; 
    } 
} 

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

работы с компактной структурой 2.0. Charset.Ansi не реализовано – mircoso

+0

Я пробую «C: \ Program Files (x86) \ Microsoft.NET \ SDK \ CompactFramework \ v2.0 \ WindowsCE \ mscorlib.dll", и в эту библиотеку не входит Cdecl. может, мой либрай устарел? – mircoso

0

Я хотел бы сделать это как этот

 [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

Я пытаюсь найти решение, но исключаю исключение в Marshal.SizeOf (allParameters) с исключением: NotsupportedException. enum CallingConvention содержит только один элемент WinApi. (Я использую Framework: Compact Framework 2.0 и VS 2008). не понимаю, почему .... – mircoso

+0

Убедитесь, что вы используете последний код и структуры.Я получал подобные ошибки с оригинальным размещенным кодом и делал изменения. Опубликованный код больше не дает этой ошибки. Значение «z» равно 1400 = 50 * 28, что является правильным. Таким образом, код передает LPTR ptr в предварительно выделенный блок памяти 1400 байт в неуправляемом пространстве памяти. – jdweng

+0

Вы можете попробовать это вместо: int z = Marshal.SizeOf (allParameters.GetType()); – jdweng