Usuário com melhor resposta
dllimport de c++ para c# como passar estrutura

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?
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
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.
- Mesclado AndreAlvesLimaModerator terça-feira, 27 de julho de 2010 16:40 mesmo assunto, mesmo autor
-
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
-
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
-
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)- Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 27 de julho de 2010 16:36
-
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
-
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?
-
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
-
-
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