2014-10-22 3 views
3

Я использую DLL, написанный на C++ в моем проекте C#, используя DllImport и одну из функций, которые я использую, выглядит так:C++ Struct в C#

[DllImport("dds.dll", CharSet = CharSet.Auto)] 
    private static extern int Par(
     ddTableResults2 tableResult, 
     ref parResults ParResult, 
     int vul 
    ); 

parResults структура определена в C++ как это:

struct parResults { 
    /* index = 0 is NS view and index = 1 
    is EW view. By 'view' is here meant 
    which side that starts the bidding. */ 
    char   parScore[2][16]; 
    char   parContractsString[2][128]; 
}; 

начало C++ функция

int STDCALL Par(struct ddTableResults * tablep, struct parResults *presp, 
    int vulnerable) 

Как следует определить выше структуры в C#, чтобы иметь возможность отправлять эта структура как ссылка в функцию DLL?

Это то, что я пытался, но не работают на всех, и я просто получаю нарушение прав доступа Ошибка

[StructLayout(LayoutKind.Sequential)] 
    public struct parResults 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
     public char[,] parScore; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
     public char[,] parContractsString; 

     public parResults(int x) 
     { 
      parScore = new char[2,16]; 
      parContractsString = new char[2,128]; 
     } 
    } 
+1

Я думаю, что для начала вам следует опубликовать истинное определение структуры C++ и функцию, которую вы импортируете. Поддельная версия созданной вами структуры оставляет нам интересно, что еще изменилось из кода, который компилируется, и кода, который вы разместили. –

+0

Я посмотрю, смогу ли я его найти! – StefanE

+1

Как насчет 'struct ddTableResults'? Как это объявлено в C++ и C#. Почему это не передано ref в C#? –

ответ

2

Это довольно сложная структура маршалу в C#. Существуют различные способы его попытки, но я думаю, что было бы самым чистым представлять массивы символов в виде массивов байтов и маршала в строки и из строк вручную. Вот демонстрация того, что я имею в виду:

C++

#include <cstring> 

struct parResults { 
    char   parScore[2][16]; 
    char   parContractsString[2][128]; 
}; 

extern "C" 
{ 
    __declspec(dllexport) void foo(struct parResults *res) 
    { 
     strcpy(res->parScore[0], res->parContractsString[0]); 
     strcpy(res->parScore[1], res->parContractsString[1]); 
    } 
} 

C#

using System; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     class parResults 
     { 
      private const int parScoreCount = 2; 
      private const int parScoreLen = 16; 
      private const int parContractsStringCount = 2; 
      private const int parContractsStringLen = 128; 

      [MarshalAs(UnmanagedType.ByValArray, 
       SizeConst = parScoreCount * parScoreLen)] 
      private byte[] parScoreBuff; 

      [MarshalAs(UnmanagedType.ByValArray, 
       SizeConst = parContractsStringCount * parContractsStringLen)] 
      private byte[] parContractsStringBuff; 

      public string getParScore(int index) 
      { 
       string str = Encoding.Default.GetString(parScoreBuff, 
        index * parScoreLen, parScoreLen); 
       int len = str.IndexOf('\0'); 
       if (len != -1) 
        str = str.Substring(0, len); 
       return str; 
      } 

      public void setParScore(int index, string value) 
      { 
       byte[] bytes = Encoding.Default.GetBytes(value); 
       int len = Math.Min(bytes.Length, parScoreLen); 
       Array.Copy(bytes, 0, parScoreBuff, index * parScoreLen, len); 
       Array.Clear(parScoreBuff, index * parScoreLen + len, 
        parScoreLen - len); 
      } 

      public string parContractsString(int index) 
      { 
       string str = Encoding.Default.GetString(parContractsStringBuff, 
        index * parContractsStringLen, parContractsStringLen); 
       int len = str.IndexOf('\0'); 
       if (len != -1) 
        str = str.Substring(0, len); 
       return str; 
      } 

      public void setParContractsString(int index, string value) 
      { 
       byte[] bytes = Encoding.Default.GetBytes(value); 
       int len = Math.Min(bytes.Length, parContractsStringLen); 
       Array.Copy(bytes, 0, parContractsStringBuff, 
        index * parContractsStringLen, len); 
       Array.Clear(parContractsStringBuff, 
        index * parContractsStringLen + len, 
        parContractsStringLen - len); 
      } 

      public parResults() 
      { 
       parScoreBuff = new byte[parScoreCount * parScoreLen]; 
       parContractsStringBuff = 
        new byte[parContractsStringCount * parContractsStringLen]; 
      } 
     }; 

     [DllImport(@"...", CallingConvention = CallingConvention.Cdecl)] 
     static extern void foo([In,Out] parResults res); 

     static void Main(string[] args) 
     { 
      parResults res = new parResults(); 
      res.setParContractsString(0, "foo"); 
      res.setParContractsString(1, "bar"); 
      foo(res); 
      Console.WriteLine(res.getParScore(0)); 
      Console.WriteLine(res.getParScore(1)); 
      Console.ReadLine(); 
     } 
    } 
} 

Здесь я использовал класс для представления структуры. Поскольку класс в C# является ссылкой, мы не объявляем параметры этого типа с ref. Я также использовал __cdecl для удобства, чтобы избежать того, что будет оформлено имя функции. Но ваша библиотека использовала __stdcall, и поэтому вам нужно придерживаться этого.

Класс демонстрирует отправку данных в обоих направлениях. Вероятно, вы могли бы упростить код, если поток данных был более ограниченным.