Resumo do uso de DllImport em C #

(virar)

Recentemente usei o DllImport e descobri que a maior parte do conteúdo é o mesmo do Baidu na Internet, e eu o coletei do MSDN. Agora vou resumir o conteúdo e compartilhar com você.

 

Ao estudar C # no trabalho real , você pode perguntar: Por que temos que reescrever o código de algumas funções existentes (como algumas funções no Windows, alguns métodos já escritos em C ++), existe alguma maneira de escrever C # diretamente ? você usa essas funções que já existem? A resposta é sim, você pode chamar diretamente essas funções por meio de DllImport em C #.
DllImport é uma classe de atributo no namespace System.Runtime.InteropServices, portanto, se quiser usar DllImport no ASP.NET, você deve primeiro "using System.Runtime.InteropServices;". Sua função é fornecer informações necessárias para chamar funções derivadas de DLLs não gerenciadas. O atributo DllImport é aplicado ao método e requer pelo menos o nome da dll que contém o ponto de entrada. Definição de atributo DllImport

do seguinte modo:
namespace System.Runtime.InteropServices
   {
  
  
    [AttributeUsage (AttributeTargets.Method)]
    public class DllImportAttribute: System.Attribute
    {
  
  

 

 

public DllImportAttribute (string dllName) {...} // O parâmetro de posicionamento é dllName
public CallingConvention CallingConvention; // Convenção de chamada do ponto de entrada
public CharSet CharSet; // Conexão de caracteres usada pelo ponto de entrada
public string EntryPoint; // Nome do ponto de entrada
public bool ExactSpelling; // Se a grafia deve ser exatamente igual ao ponto de entrada indicado, o padrão é falso
public bool PreserveSig; // A assinatura do método é preservada ou convertida
public bool SetLastError; // O valor de retorno do método FindLastError é armazenado aqui
public string Value {get {...}}                            

 

 

    } 
}
Descrição:
1. DllImport só pode ser colocado em declarações de método.
2. DllImport tem um único parâmetro de posicionamento: especifique o parâmetro dllName que contém o nome dll do método importado.
3. DllImport tem cinco parâmetros nomeados:
   a. O parâmetro CallingConvention indica a convenção de chamada do ponto de entrada. Se CallingConvention não for especificado, o valor padrão CallingConvention.Winapi será usado.
   b. O parâmetro CharSet especifica o conjunto de caracteres usado no ponto de entrada. Se CharSet não for especificado, o valor padrão CharSet.Auto será usado.
   c. O parâmetro EntryPoint fornece o nome do ponto de entrada na dll. Se EntryPoint não for especificado, o nome do próprio método será usado.
   d. O parâmetro ExactSpelling indica se o EntryPoint deve corresponder exatamente à grafia do ponto de entrada indicado. Se ExactSpelling não for especificado, o valor padrão false será usado.
   e. O parâmetro PreserveSig indica se a assinatura do método é preservada ou convertida. Quando a assinatura é convertida, ela é convertida em uma assinatura com um valor de retorno HRESULT e um parâmetro de saída adicional denominado retval com o valor de retorno. Se PreserveSig não for especificado, o valor padrão true será usado.
   f. O parâmetro SetLastError indica se o método retém o "último erro" do Win32. Se SetLastError não for especificado, o valor padrão false será usado.
4. É uma classe de atributo única.
5. O método modificado com o atributo DllImport deve ter o modificador externo.
Exemplo de uso de DllImport (um win32api usado para escrever arquivos ini):
 DllImport ("kernel32")
 private static extern long WritePrivateProfileString (seção string, chave string, string val, string filePath);
O tipo de dados de chamada WinAPI com este método corresponde a: DWORD = int ou uint, BOOL = bool, constante predefinida = enum, structure = struct.

 

Problema de caminho DllImport:

 

O DllImport encontrará automaticamente os lugares em ordem: 
1. O diretório onde o exe está localizado 
2. Diretório System32 
3. Diretório de variável de ambiente

Portanto, você só precisa copiar a DLL referenciada para esses três diretórios e não precisa escrever o caminho.

 

 

Na web, mas também no aplicativo
Posteriormente, foi descoberto que usando [DllImport (@ "C: \ OJ \ Bin \ Judge.dll")] para especificar o caminho absoluto da DLL pode ser carregado normalmente.
Esse problema ocorre com mais frequência ao usar componentes DLL não gerenciados de terceiros. O meu também é o problema no momento. A solução oficial da Equipe Asp.Net é a seguinte:
Primeiro, você precisa confirmar quais componentes você faz referência, quais são gerenciados e quais não são gerenciados. Gerenciado é fácil de manusear, o uso direto precisa ser cotado e o uso indireto precisa ser copiado para o diretório bin. O processamento não gerenciado será mais problemático. Na verdade, você copiar para bin não ajudará, porque o CLR copiará os arquivos para um diretório temporário e, em seguida, executará a web lá, e o CLR copiará apenas os arquivos gerenciados, é por isso que colocamos claramente os dlls não gerenciados em Ele ainda informa que o módulo não pode ser carregado no compartimento.
A abordagem específica é a seguinte:
Em primeiro lugar, podemos encontrar um local no servidor para criar um novo diretório, se for C: \ DLL;
Então, na variável de ambiente, adicione este diretório à variável Path;
Por fim, copie todos os arquivos não gerenciados para C: \ DLL ou, mais simplesmente, coloque a DLL no diretório system32.
Para aplicações que podem ser implantadas por si mesmas, tal excepcional não é uma solução, porém, se estivermos usando espaço virtual, não podemos registrar a variável PATH ou copiar nossa própria DLL para o diretório system32. Ao mesmo tempo, não conhecemos necessariamente o caminho físico de nossa DLL.
Apenas constantes de string podem ser usadas em DllImport, e Server.MapPath (@ "~ / Bin / Judge.dll") não pode ser usado para determinar o caminho físico.
 
O problema da baixa velocidade de carregamento do DllImport:
No entanto, descobri que chamar essa "DLL não gerenciada" é muito lento, talvez porque meu método exija autenticação remota, mas é muito lento. Depois de muita pesquisa, finalmente encontrei uma solução perfeita.
Primeiro usamos
[DllImport ("kernel32.dll")]
private extern static IntPtr LoadLibrary (String path);
[DllImport ("kernel32.dll")]
private extern static IntPtr GetProcAddress (IntPtr lib, String funcName);
[DllImport ("kernel32.dll")]
private extern static bool FreeLibrary (IntPtr lib);
Os endereços das funções LoadLibrary e GetProcAddress são obtidos respectivamente e, em seguida, as funções em nossa DLL são obtidas por meio dessas duas funções.
Podemos primeiro usar Server.MapPath (@ "~ / Bin / Judge.dll") para obter o caminho físico de nossa DLL, então usar LoadLibrary para carregar e, finalmente, usar GetProcAddress para obter o endereço da função a ser usada.
O seguinte código de classe personalizada conclui o carregamento e a chamada de função de LoadLibrary:
public class DllInvoke
    {
  
  
 
        [DllImport ("kernel32.dll")]
        private extern static IntPtr LoadLibrary (String path);
        [DllImport ("kernel32.dll")]
        private extern static IntPtr GetProcAddress (IntPtr lib, String funcName);
        [DllImport ("kernel32.dll")]
        private extern static bool FreeLibrary (IntPtr lib);
        private IntPtr hLib;
        public DllInvoke (String DLLPath)
        {
  
  
            hLib = LoadLibrary (DLLPath);
        }
        ~ DllInvoke ()
        {
  
  
            FreeLibrary (hLib);          
        }
        // Converte a função a ser executada em um delegado
        Public Delegate Invoke (String APIName, Type t)
        {
  
  
            IntPtr api = GetProcAddress (hLib, APIName);
            return (Delegate) Marshal.GetDelegateForFunctionPointer (api, t);
        }
}
O código a seguir faz a chamada
delegado público int Compile (comando String, StringBuilder inf); // 编译
DllInvoke dll = new DllInvoke (Server.MapPath (@ "~ / Bin / Judge.dll"));
Compilar compilar = (Compilar) dll.Invoke ("Compilar", typeof (Compilar));
StringBuilder inf;
compile (@ "gcc ac -o a.exe", inf); // aqui é para chamar a função Compile definida em minha DLL
 
Exemplo de uso de DllImport:
Biblioteca usada em uma programação Win32 C #
  usada tipo correspondente:
1. DWORD é um número inteiro de 4 bytes, portanto, podemos usar int ou uint como o tipo correspondente em C #.
2. O tipo bool corresponde a BOOL.
Exemplo 1 : chame a API Beep () para fazer um som
Beep () é definido em kernel32.lib. Conforme definido no MSDN, Beep tem o seguinte protótipo:
BOOL Beep (DWORD dwFreq, // frequência do som
          DWORD dwDuration // duração do som); 
Escreva o seguinte protótipo em C #:
[DllImport ("kernel32.dll")] 
public static extern bool Beep (frequência interna, duração interna);
Exemplo 2 : tipos e constantes enumerados
MessageBeep () é definido em user32.lib. Conforme definido no MSDN, MessageBeep tem o seguinte protótipo:
BOOL MessageBeep (UINT uType // tipo de som
                  ); 
Escreva o protótipo em C #:
public enum BeepType
{
  
  
   SimpleBeep = -1,
   IconAsterisk = 0x00000040,
   IconExclamation = 0x00000030,
   IconHand = 0x00000010,
   IconQuestion = 0x00000020,
   Ok = 0x00000000,
}
Na verdade, o parâmetro uType aceita um conjunto de constantes predefinidas. Para o parâmetro uType, faz sentido usar o tipo enum.
[DllImport ("user32.dll")]
public static extern boolMessageBeep (BeepType beepType);
Exemplo 3 : Estrutura de processamento
Às vezes, preciso determinar a condição da bateria do meu laptop. O Win32 fornece funções de gerenciamento de energia para essa finalidade. Pesquise no MSDN para localizar a função GetSystemPowerStatus ().
BOOL GetSystemPowerStatus (LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
Esta função contém um ponteiro para uma estrutura, da qual ainda não tratamos. Para lidar com a estrutura, precisamos definir a estrutura em C #. Começamos com a definição de não gerenciado:
typedef struct _SYSTEM_POWER_STATUS {
  
  
   BYTE ACLineStatus;
   BYTE BatteryFlag;
   BYTE BatteryLifePercent;
   BYTE Reservado1;
   DWORD BatteryLifeTime;
   DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, * LPSYSTEM_POWER_STATUS;
Em seguida, obtenha a versão C # substituindo os tipos C # por tipos C.
struct SystemPowerStatus
{
  
  
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  byte reserved1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}
    Dessa forma, você pode facilmente escrever um protótipo C #:
    [DllImport ("kernel32.dll")]
    public static extern bool GetSystemPowerStatus (ref SystemPowerStatus systemPowerStatus);
Neste protótipo, usamos "ref" para indicar que o ponteiro da estrutura será passado em vez do valor da estrutura. Essa é a maneira geral de lidar com estruturas passadas por ponteiros.
Esta função funciona bem, mas é melhor definir os campos ACLineStatus e batteryFlag como enum:
enum ACLineStatus: byte
{
  
  
   Offline = 0,
   Online = 1,
   Desconhecido = 255,
}
enum BatteryFlag: byte
{
  
  
   Alto = 1,
   Baixo = 2,
   Crítico = 4,
   Carregando = 8,
   NoSystemBattery = 128,
   Desconhecido = 255,
}
Observe que, como os campos da estrutura são bytes, usamos byte como o tipo básico de enum.
Chamando código C ++ em C #
tipo int
[DllImport (“MyDLL.dll")] 
public static extern int mySum (int a1, int b1); // retorna um tipo int
extern “C” __declspec (dllexport) int WINAPI mySum (int a2, int b2) // Declarado na DLL
{ 
    // a2 b2 não pode mudar a1 b1
    // a2 = ..
    // b2 = ...
 retornar a + b;
}
// Tipo de transferência de parâmetro público estático extern int mySum (ref int a1, ref int b1); // Declara extern "C" na DLL __declspec (dllexport) int WINAPI mySum (int * a2, int * b2) {// Sim Alterar a1, b1 * a2 = ... * b2 = ... retornar a + b;}

DLL precisa passar em char * type  [DllImport ("MyDLL.dll")] // Passar valor public static extern int mySum (string astr1, string bstr1); // Declare extern "C" em DLL __declspec (dllexport) int WINAPI mySum (char * astr2, char * bstr2) {// Alterar astr2bstr 2, astr1 bstr1 não será alterado return a + b;}

DLL precisa enviar char * type [DllImport ("MyDLL.dll")] // o valor enviado public static extern int mySum (StringBuilder abuf, StringBuilder bbuf); // Declare extern "C" na DLL __declspec (dllexport ) int WINAPI mySum (char * astr, char * bstr) {// outgoing char * change astr bstr -> abuf, bbuf pode ser alterado return a + b;} Função de retorno de chamada DLL BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARAM lParam)

usingSystem; 
using System.Runtime.InteropServices; 
público delegado bool CallBack (int hwnd, int lParam); // 定义 委托 函数 类型
public class EnumReportApp 
{ 
   [DllImport ("user32")] 
   public static extern int EnumWindows (CallBack x, int y); 
   public static void Main ()
   { 
     CallBack myCallBack = novo CallBack (EnumReportApp.Report);
     EnumWindows (myCallBack, 0); 
   } 
   public static bool Report (int hwnd, int lParam) 
   { 
      Console.Write ("Window handle is"); 
      Console.WriteLine (hwnd); return true; 
   } 
}

DLL 传递 结构 BOOL PtInRect (const RECT * lprc, POINT pt); using System.Runtime.InteropServices; [StructLayout (LayoutKind.Sequential)] public struct Point

{public int x; public int y; } [StructLayout (LayoutKind.Explicit)] public struct Rect {[FieldOffset (0)] public int left; [FieldOffset (4)] public int top; [FieldOffset (8)] direito interno público; [FieldOffset (12)] public int bottom; } Classe XXXX

{[DllImport ("User32.dll")] public static extern bool PtInRect (ref Rect r, Point p); }

Acho que você gosta

Origin blog.csdn.net/u014780302/article/details/100740111
Recomendado
Clasificación