Resumen del uso de DllImport en C #

(giro)

Recientemente utilicé DllImport y descubrí que la mayor parte del contenido es el mismo de Baidu en Internet, y lo recopilé de MSDN. Ahora resumiré el contenido y lo compartiré con ustedes.

 

Cuando estudie C # en el trabajo real , puede preguntar: ¿Por qué tenemos que reescribir el código para algunas funciones existentes (como algunas funciones en Windows, algunos métodos ya escritos en C ++), hay alguna forma de escribir directamente C #? ¿Usas estas funciones que ya existen? La respuesta es sí, puede llamar directamente a estas funciones a través de DllImport en C #.
DllImport es una clase de atributo en el espacio de nombres System.Runtime.InteropServices, por lo que si desea utilizar DllImport en ASP.NET, primero debe "utilizar System.Runtime.InteropServices;". Su función es proporcionar la información necesaria para llamar a funciones derivadas de DLL no administradas. El atributo DllImport se aplica al método y requiere al menos el nombre de la dll que contiene el punto de entrada. Definición del atributo DllImport

como sigue:
espacio de nombres System.Runtime.InteropServices
   {
  
  
    [AttributeUsage (AttributeTargets.Method)]
    clase pública DllImportAttribute: System.Attribute
    {
  
  

 

 

public DllImportAttribute (string dllName) {...} // El parámetro de posicionamiento es dllName
public CallingConvention CallingConvention; // Convención de llamada de punto de entrada
public CharSet CharSet; // Conexión de caracteres utilizada por el punto de entrada
public string EntryPoint; // Nombre del punto de entrada
public bool ExactSpelling; // Si la ortografía debe ser exactamente la misma que la del punto de entrada indicado, el valor predeterminado es falso
public bool PreserveSig; // Es la firma del método preservada o convertida
public bool SetLastError; // El valor de retorno del método FindLastError se almacena aquí
Valor de cadena pública {get {...}}                            

 

 

    } 
}
Descripción:
1. DllImport solo se puede colocar en declaraciones de métodos.
2. DllImport tiene un único parámetro de posicionamiento: especifique el parámetro dllName que contiene el nombre dll del método importado.
3. DllImport tiene cinco parámetros con nombre:
   a. El parámetro CallingConvention indica la convención de llamada del punto de entrada. Si no se especifica CallingConvention, se usa el valor predeterminado CallingConvention.Winapi.
   b) El parámetro CharSet especifica el juego de caracteres utilizado en el punto de entrada. Si no se especifica CharSet, se utiliza el valor predeterminado CharSet.Auto.
   c. El parámetro EntryPoint proporciona el nombre del punto de entrada en la dll. Si no se especifica EntryPoint, se utiliza el nombre del método en sí.
   d) El parámetro ExactSpelling indica si EntryPoint debe coincidir exactamente con la ortografía del punto de entrada indicado. Si no se especifica ExactSpelling, se utiliza el valor predeterminado de falso.
   e) El parámetro PreserveSig indica si la firma del método se conserva o se convierte. Cuando se convierte la firma, se convierte en una firma con un valor de retorno HRESULT y un parámetro de salida adicional llamado retval con el valor de retorno. Si no se especifica PreserveSig, se usa el valor predeterminado de verdadero.
   f. El parámetro SetLastError indica si el método retiene el "último error" de Win32. Si no se especifica SetLastError, se utiliza el valor predeterminado de false.
4. Es una clase de atributo de una sola vez.
5. El método modificado con el atributo DllImport debe tener el modificador extern.
Ejemplo de uso de DllImport (un win32api usado para escribir archivos ini):
 DllImport ("kernel32")
 private static extern long WritePrivateProfileString (sección de cadena, clave de cadena, cadena val, cadena filePath);
El tipo de datos de llamar a WinAPI con este método corresponde a: DWORD = int o uint, BOOL = bool, constante predefinida = enum, structure = struct.

 

Problema de ruta de DllImport:

 

DllImport encontrará automáticamente los lugares en orden: 
1. El directorio donde se encuentra el exe 
2. Directorio System32 
3. Directorio de variables de entorno

Por lo tanto, solo necesita copiar la DLL a la que se hace referencia en estos tres directorios y no necesita escribir la ruta.

 

 

En la web, pero también en la aplicación
Más tarde, se descubrió que el uso de [DllImport (@ "C: \ OJ \ Bin \ Judge.dll")] para especificar la ruta absoluta de la DLL se puede cargar normalmente.
Este problema ocurre con mayor frecuencia cuando se utilizan componentes DLL no administrados de terceros. El mío también es el problema en este momento. La solución oficial de Asp.Net Team es la siguiente:
Primero, debe confirmar a qué componentes hace referencia, cuáles están administrados y cuáles no. Administrado es fácil de manejar, el uso directo debe cotizarse y el uso indirecto debe copiarse en el directorio bin. El procesamiento no administrado será más molesto. De hecho, copiar a bin no ayudará, porque CLR copiará los archivos a un directorio temporal y luego ejecutará la web allí, y CLR solo copiará los archivos administrados, por lo que claramente colocamos los dlls no administrados en Todavía indica que el módulo no se puede cargar debajo del contenedor.
El enfoque específico es el siguiente:
En primer lugar, podemos encontrar un lugar en el servidor para crear un nuevo directorio, si es C: \ DLL;
Luego, en la variable de entorno, agregue este directorio a la variable Path;
Finalmente, copie todos los archivos no administrados a C: \ DLL, o más simplemente coloque el DLL en el directorio system32.
Para aplicaciones que se pueden desplegar por sí mismas, este sobresaliente no es una solución, sin embargo, si estamos usando espacio virtual, no podemos registrar la variable PATH o copiar nuestra propia DLL al directorio system32. Al mismo tiempo, no necesariamente conocemos el camino físico de nuestra Dll.
Solo se pueden usar constantes de cadena en DllImport, y Server.MapPath (@ "~ / Bin / Judge.dll") no se puede usar para determinar la ruta física.
 
El problema de la velocidad de carga lenta de DllImport:
Sin embargo, descubrí que llamar a esta "Dll ​​no administrada" es bastante lento, tal vez porque mi método requiere autenticación remota, pero es demasiado lento. Después de mucha investigación, finalmente encontré una solución perfecta.
Primero usamos
[DllImport ("kernel32.dll")]
Private extern static IntPtr LoadLibrary (ruta de cadena);
[DllImport ("kernel32.dll")]
private extern static IntPtr GetProcAddress (IntPtr lib, String funcName);
[DllImport ("kernel32.dll")]
Private extern static bool FreeLibrary (IntPtr lib);
Las direcciones de las funciones LoadLibrary y GetProcAddress se obtienen respectivamente, y luego las funciones en nuestra DLL se obtienen a través de estas dos funciones.
Primero podemos usar Server.MapPath (@ "~ / Bin / Judge.dll") para obtener la ruta física de nuestra DLL, luego usar LoadLibrary para cargar, y finalmente usar GetProcAddress para obtener la dirección de la función a usar.
El siguiente código de clase personalizada completa la carga y la llamada de función de LoadLibrary:
clase pública DllInvoke
    {
  
  
 
        [DllImport ("kernel32.dll")]
        Private extern static IntPtr LoadLibrary (ruta de cadena);
        [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);          
        }
        // Convertir la función a ejecutar en un delegado
        Invocación de delegado público (cadena APIName, tipo t)
        {
  
  
            IntPtr api = GetProcAddress (hLib, APIName);
            return (Delegado) Marshal.GetDelegateForFunctionPointer (api, t);
        }
}
El siguiente código hace la llamada
public delegate int Compile (comando String, StringBuilder inf); // 编译
DllInvoke dll = nuevo DllInvoke (Server.MapPath (@ "~ / Bin / Judge.dll"));
Compile compile = (Compile) dll.Invoke ("Compile", typeof (Compile));
StringBuilder inf;
compile (@ "gcc ac -o a.exe", inf); // aquí es para llamar a la función Compilar definida en mi DLL
 
Ejemplo de uso de DllImport:
La biblioteca utilizada en una programación de Win32 C #
  utilizó el tipo correspondiente:
1. DWORD es un entero de 4 bytes, por lo que podemos usar int o uint como el tipo correspondiente de C #.
2. El tipo bool corresponde a BOOL.
Ejemplo 1 : llamar a la API de Beep () para hacer un sonido
Beep () se define en kernel32.lib. Como se define en MSDN, Beep tiene el siguiente prototipo:
BOOL Beep (DWORD dwFreq, // frecuencia de sonido
          DWORD dwDuration // duración del sonido); 
Escriba el siguiente prototipo en C #:
[DllImport ("kernel32.dll")] 
public static extern bool Beep (frecuencia int, duración int);
Ejemplo 2 : tipos y constantes enumerados
MessageBeep () se define en user32.lib. Como se define en MSDN, MessageBeep tiene el siguiente prototipo:
BOOL MessageBeep (UINT uType // tipo de sonido
                  ); 
Escriba el prototipo en C #:
public enum BeepType
{
  
  
   SimpleBeep = -1,
   IconAsterisk = 0x00000040,
   IconExclamation = 0x00000030,
   IconHand = 0x00000010,
   IconQuestion = 0x00000020,
   Ok = 0x00000000,
}
El parámetro uType en realidad acepta un conjunto de constantes predefinidas. Para el parámetro uType, tiene sentido usar el tipo enum.
[DllImport ("user32.dll")]
public static extern boolMessageBeep (BeepType beepType);
Ejemplo 3 : estructura de procesamiento
A veces necesito determinar el estado de la batería de mi computadora portátil. Win32 proporciona funciones de administración de energía para este propósito. Busque en MSDN para encontrar la función GetSystemPowerStatus ().
BOOL GetSystemPowerStatus (LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
Esta función contiene un puntero a una estructura, que aún no hemos tratado. Para lidiar con la estructura, necesitamos definir la estructura en C #. Comenzamos con la definición de no administrado:
typedef struct _SYSTEM_POWER_STATUS {
  
  
   BYTE ACLineStatus;
   BYTE BatteryFlag;
   BYTE BatteryLifePercent;
   BYTE Reservado1;
   DWORD BatteryLifeTime;
   DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, * LPSYSTEM_POWER_STATUS;
Luego, obtenga la versión de C # sustituyendo los tipos de C por los tipos de C #.
struct SystemPowerStatus
{
  
  
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  byte reservado1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}
    De esta manera, puede escribir fácilmente un prototipo de C #:
    [DllImport ("kernel32.dll")]
    public static extern bool GetSystemPowerStatus (ref SystemPowerStatus systemPowerStatus);
En este prototipo, usamos "ref" para indicar que se pasará el puntero de estructura en lugar del valor de estructura. Ésta es la forma general de tratar las estructuras pasadas por punteros.
Esta función funciona bien, pero es mejor definir los campos ACLineStatus y batteryFlag como enum:
enumeración ACLineStatus: byte
{
  
  
   Fuera de línea = 0,
   En línea = 1,
   Desconocido = 255,
}
enum BatteryFlag: byte
{
  
  
   Alto = 1,
   Bajo = 2,
   Crítico = 4,
   Cargando = 8,
   NoSystemBattery = 128,
   Desconocido = 255,
}
Tenga en cuenta que dado que los campos de la estructura son bytes, usamos byte como el tipo básico de la enumeración.
Llamar al código C ++ en C #
tipo int
[DllImport ("MyDLL.dll")] 
public static extern int mySum (int a1, int b1); // devuelve un tipo int
extern "C" __declspec (dllexport) int WINAPI mySum (int a2, int b2) // Declarado en DLL
{ 
    // a2 b2 no puede cambiar a1 b1
    // a2 = ..
    // b2 = ...
 devuelve a + b;
}
// Transferencia de parámetros int tipo public static extern int mySum (ref int a1, ref int b1); // Declare extern "C" en la DLL __declspec (dllexport) int WINAPI mySum (int * a2, int * b2) {// Sí Cambiar a1, b1 * a2 = ... * b2 = ... return a + b;}

DLL debe pasar char * type  [DllImport ("MyDLL.dll")] // Pasar valor public static extern int mySum (string astr1, string bstr1); // Declarar extern "C" en DLL __declspec (dllexport) int WINAPI mySum (char * astr2, char * bstr2) {// Cambiar astr2bstr 2, astr1 bstr1 no cambiará return a + b;}

DLL necesita enviar char * type [DllImport ("MyDLL.dll")] // el valor enviado public static extern int mySum (StringBuilder abuf, StringBuilder bbuf); // Declare extern "C" en la DLL __declspec (dllexport ) int WINAPI mySum (char * astr, char * bstr) {// char saliente * cambiar astr bstr -> abuf, bbuf se puede cambiar return a + b;} Función de devolución de llamada DLL BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARAM lParam)

usingSystem; 
utilizando System.Runtime.InteropServices; 
delegado público bool CallBack (int hwnd, int lParam); // 定义 委托 函数 类型
public class EnumReportApp 
{ 
   [DllImport ("user32")] 
   public static extern int EnumWindows (CallBack x, int y); 
   vacío estático público Main ()
   { 
     CallBack myCallBack = new CallBack (EnumReportApp.Report);
     EnumWindows (myCallBack, 0); 
   } 
   Informe bool estático público (int hwnd, int lParam) 
   { 
      Console.Write ("El identificador de la ventana es"); 
      Console.WriteLine (hwnd); devuelve verdadero; 
   } 
}

DLL 传递 结构 BOOL PtInRect (const RECT * lprc, POINT pt); utilizando System.Runtime.InteropServices; [StructLayout (LayoutKind.Sequential)] punto de estructura pública

{public int x; public int y; } [StructLayout (LayoutKind.Explicit)] public struct Rect {[FieldOffset (0)] public int left; [FieldOffset (4)] public int top; [FieldOffset (8)] public int right; [FieldOffset (12)] public int bottom; } Clase XXXX

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

Supongo que te gusta

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