none
dllimport de c++ para c# como passar estrutura RRS feed

  • Pergunta

  •  

     

    Preciso passar uma estrutura do c# para um método em uma dll em c++.

    Estrutura:

    public
     struct
     Est
    {
    float vetor[]; float max;
    float min; }

    Método em c#:

     

    [DllImport("minha.dll")]
    private static extern int func(ref Est est);

    public void test() { Est est = new Est(); est.vetor = new vetor[10]; func(ref est);
    }

     

    Assinatura do método em c++ e estrutura em c++.

     

    extern
     "C"
     __declspec (dllexport
    ) int
     func(EST* est);
    
    struct
     EST
    {
    float
    * vetor;
    float
     max;
    float
     min;
    }
    

     

    Da erro de acesso a memória. Alguem sabe uma forma melhor de fazer isso?

     

     

    terça-feira, 27 de julho de 2010 12:23

Respostas

  • Deusiro,

    Neste caso, anotando da seguinte forma funciona:

     

     public struct FloatStruct{
      [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_R4)]
    	 public float[] floatArray;
      public int floatCount;
      public float float1;
      public float float2;
     }

     

    Copiei a struct de um exemplo que fiz aqui.... me diga se funcionou.

     

    Abraço,

    Eric

    • Marcado como Resposta PedroDD sexta-feira, 30 de julho de 2010 20:49
    sexta-feira, 30 de julho de 2010 20:40

Todas as Respostas

  • Tenho uma dll: minha.dll

    Dela tem um método:

    extern "C" __declspec (dllexport) int Metodo(float* vetor, int tamanho);

    Na classe em C# eu importo a dll:

    [DllImport("minha.dll")]
    private static extern int Metodo(float[] vetor, int tamanho);

    Tem algum problema no que eu estou fazendo?Estah funcionando perfeito, mas n estou muito certo qto a possíveis problema devido ao GC.


     

    segunda-feira, 26 de julho de 2010 21:18
  • Deusiro,

    A questão é que ando existe essa conversa managed x unmanaged a representação interna da memória não necessariamente é a mesma.

    Nesse caso, vc precisa fazer um:

    IntPtr p = Marshal.AllocHGlobal(Size);
    Marshal.Copy(seuFloatArray, 0, p, Size);
    Metodo(p, Size);
    Marshal.FreeHGlobal(p);
    

    Acho que é por aí.

    Você precisa alocar, através de AllocHGlobal, memória "não gerenciada", copiar o teu array gerenciado para um teco de memória não gerenciada, chamar o método, liberar a memória não gerenciada.

    Size, tem que ter o tamanho do buffer não gerenciado para caber o array. No teu caso, acredito que o tamanho do array * 4 (4 bytes por float, ou seja, 32 bits).

    Acho que o artigo abaixo pode te ajudar:

    http://ericlemes.com/2010/06/23/dotnet-interop-pt/

    Infelizmente, neste caso tem que haver a cópia do array, o que não é eficiente. 

     

    Abraço,

    Eric

    terça-feira, 27 de julho de 2010 12:24
  • Funciona da forma q estou fazendo, pq serah?

    Nao ser eficiente eh um problema para mim pois trabalho com tempos da ordem de 1 ms.

    uma forma seria fazer fixed em: &vetor[0], passar o ponteiro, mudar os valores dentro da dll em c++ e depois sair do fixed.

    Meu problema agora eh passar uma struct com float[] dentro dela.. outro topico

     

    vlw

    terça-feira, 27 de julho de 2010 13:03
  • Ola

    Realmente isso é um pouco complexo visto que há diferenças entre uma Struct em C# e outra em C++. Eu vi esse artigo abaixo que é mais ou menos o que vc quer (pelo menos é o que eu entendi)

    http://stackoverflow.com/questions/31854/how-to-marshal-an-array-of-structs-net-c-c

     

    Att


    William John Adam Trindade
    Analyste-programmeur
    ----------------------------------------------------------

    SOGI INFORMATIQUE LTÉE (http://www.sogi.com)
    terça-feira, 27 de julho de 2010 14:59
    Moderador
  • Deusiro,

    Na verdade quando você anota com DllImport e põe os tipos, o Platform Invoke já faz algumas cópias e traduções, nesse caso ele fez automaticamente.

    Alguns tipos ele consegue compatibilizar, outros não. Muitas vezes dependendo da forma como o código não gerenciado acessa a informação (retornar strings é um divertido), você pode ter que usar alguns artifícios diferentes.

     

    Abraço,

    Eric

    terça-feira, 27 de julho de 2010 16:08
  • Como eu faco agora se a estrutura tem dentro um array de float:

    struct MinhaStruct //no C#

    {

    float[] data;

    float max;

    float min;

    }

    Se no c++ eu tiver uma struct  com float* data ao inves de float[] data, vai converter automatico tb? preciso fazer alguma configuracao com o marshall?

    terça-feira, 27 de julho de 2010 16:18
  • Deusiro,

    Neste caso, anotando da seguinte forma funciona:

     

     public struct FloatStruct{
      [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_R4)]
    	 public float[] floatArray;
      public int floatCount;
      public float float1;
      public float float2;
     }

     

    Copiei a struct de um exemplo que fiz aqui.... me diga se funcionou.

     

    Abraço,

    Eric

    • Marcado como Resposta PedroDD sexta-feira, 30 de julho de 2010 20:49
    sexta-feira, 30 de julho de 2010 20:40
  • Legal cara, obrigado!

    Teria como explicar um pouco sobre as opção do Marshal que você botou?

    sexta-feira, 30 de julho de 2010 20:49
  • Deusiro,

    Não entendi exatamente quais opções da classe Marshal...

    Se for a anotação:

     [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_R4)]

    Significa o seguinte: O PInvoke vai entender que o código não gerenicado está esperando uma matriz (SafeArray), cujos elementos são VT_R4. VT_R4 significam números de ponto flutuante de 4 bytes (32 bit).

    É só uma instrução para ele saber como vai intercambiar o tipo gerenciado para não gerenciado.

    Se você não coloca essa informação, ele não sabe exatamente o que o outro lado está esperando. 


    Abraço,

    Eric

    segunda-feira, 2 de agosto de 2010 12:13