quarta-feira, 6 de julho de 2011

Usando DllImport no Csharp (C#)

Algumas vezes temos a necessidade de usarmos funções que estão em Dlls que não foram escritas em C#. Surge então, alguns problemas, como passagens de parâmetros, passagens de ponteiros, entre outros que não são diretamente compatíveis entre C# e a linguagem em que a Dll foi escrita. O Objetivo desse tutorial é introduzir a utilização do comando DllImport utilizando uma Dll que foi escrita em C. Assim teremos funções que precisaremos passar ponteiros, structs, etc que precisarão de uma compatibilização.

Primeiramente vamos criar um projeto em C++ para criarmos nossa Dll. Vou apenas colocar o código que usamos para nossas funções e structs. O restante acrescentado pelo compilador será omitido.

Assim as funções de nossa DLL são as seguintes: Observe que normalmente você já terá a Dll que será importada, aqui estamos criando para fins de demonstração.

struct dados //estrutura simples
{
int valor;
};

struct dadosString //contem string interna
{
int valor;
char nome[50];
};

extern "C"
{
__declspec(dllexport) void Printf()
{
printf ("Parabens conseguimos importar a DLL\n");
}

}

extern "C"
{
__declspec(dllexport) void Printf_M(char * mensagem)
{
printf("A mensagem que voce quer mostrar na tela:\n%s\n",mensagem);
}
}

extern "C"
{
__declspec(dllexport) int ContaCaracteres(char * mensagem)
{
int contador = 0;
while(*mensagem)
{
contador++;
mensagem++;
}

return contador;
}
}

extern "C"
{
__declspec(dllexport) char* ConverteParaMaiuscula(char * mensagem)
{
char *p;
p = mensagem;
while(*p)
{
*p = toupper(*p);
p++;
}
return mensagem;
}
}

extern "C"
{
__declspec(dllexport) void PreencheEstruturaInt(struct dados * d)
{
d->valor = 45;
}
}

extern "C"
{
__declspec(dllexport) void PreencheEstruturaString(struct dadosString * d)
{
d->valor = 55;
strcpy(d->nome,"Teste da Funcao");
}
}

Bem simples....

Nosso próximo passo será criar um projeto em CSHARP, para chamarmos nossa DLL.

Dentro de nosso projeto vamos criar uma classe chamada: operacional.cs . É nessa classe que faremos a chamada do DllImport.

Aqui está o código da nossa classe. Veja que a string “path” contém o caminho onde está a Dll, você deve ajustar para onde sua Dll está, por exemplo: path = @“C:\minhaDll”;

Importante, para usar DllImport, precisamos incluir o seguinte namespace:

using System.Runtime.InteropServices;


class operacional
{
private const string path = @"C:\Users\Eduardo\Documents\Visual Studio 2010\Projects\Dll\Debug\Dll.dll";
[StructLayout(LayoutKind.Sequential)]
public struct dados
{
public int valor;
}

public struct dadosString
{
public int valor;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst = 50)]public string nome;
}

//importa função: void Printf()
[DllImport(path)]
public static extern void Printf();

//Importa Função: void Printf_M(char * mensagem)
[DllImport(path, CallingConvention = CallingConvention.Cdecl)]
public static extern void Printf_M(string mensagem);

//Importa Função: int ContaCaracteres(char * mensagem)
[DllImport(path, CallingConvention = CallingConvention.Cdecl)]
public static extern int ContaCaracteres(string mensagem);

//Importa Função: char* ConverteParaMaiuscula(char * mensagem)
[DllImport(path, CallingConvention = CallingConvention.Cdecl)]
public static extern string ConverteParaMaiuscula(string mensagem);

//Importa Função: void PreencheEstruturaInt(struct dados * d)
[DllImport(path,CallingConvention = CallingConvention.Cdecl)]
public static extern void PreencheEstruturaInt(ref dados estrutura);

//Importa Função: PreencheEstruturaString(struct dadosString * d)
[DllImport(path,CallingConvention = CallingConvention.Cdecl)]
public static extern void PreencheEstruturaString(ref dadosString estrutura);

}

Agora a segue nosso programa de teste:

namespace ChamaDll
{
class Program
{
static void Main(string[] args)
{

int retorno=0;
string mensagem = "Teste com passagem de ponteiros";
operacional.dados estrutura;
estrutura.valor = 0;

//chamada sem parâmetros e sem valor de retorno
operacional.Printf();

//chamada com parametros
operacional.Printf_M(mensagem);

//Chamada com valor de retorno
retorno = operacional.ContaCaracteres(mensagem);
Console.WriteLine("Numero de caracteres: {0}",retorno);

//Chamada modificando o ponteiro - string
mensagem = operacional.ConverteParaMaiuscula(mensagem);
Console.WriteLine(mensagem);

//chamada com struct
Console.WriteLine("Valor da estrutura antes da chamada: {0}", estrutura.valor);
operacional.PreencheEstruturaInt(ref estrutura);
Console.WriteLine("Valor da estrutura depois da chamda: {0}", estrutura.valor);

//chama strutura que contem uma string
operacional.dadosString estruturaString;
estruturaString.nome = "NULL";
estruturaString.valor = 0;

operacional.PreencheEstruturaString(ref estruturaString);

Console.WriteLine("Nome: {0}, Idade:{1}", estruturaString.nome, estruturaString.valor);
Console.Read();
}
}
}



Resultado:

  

Nenhum comentário:

Postar um comentário