¿Puede C# usar C para encapsular la biblioteca estática en una dll para llamar funciones en la biblioteca?
Puedes conseguirlo. Modifique la biblioteca C lib en una dll, que luego puede ser llamada por C#.
Hablemos de los puntos a tener en cuenta al llamar a DLL en C#
En primer lugar, debe comprender qué está administrado y qué no está administrado. En términos generales, se puede pensar que el código no administrado se compone principalmente de componentes DLL y activeX desarrollados en base a la plataforma win
32, mientras que el código administrado se desarrolla en base a la plataforma .net.
(1) Método general para llamar a funciones no administradas en DLL
Primero, el método externo debe declararse en el programa fuente del lenguaje C#. Su forma básica es:
<. p > [DLLImport("archivo DLL")] El modificador extern devuelve el nombre del método de tipo variable (lista de parámetros)Dónde:
Archivo DLL: contiene un archivo de biblioteca que define métodos externos .
Modificadores: Modificadores de acceso, modificadores distintos de los abstractos que se pueden utilizar al declarar métodos.
Tipo de variable de retorno: el tipo de variable de retorno del método que necesita llamar en el archivo DLL.
Nombre del método: el nombre del método que necesita llamar en el archivo DLL.
Lista de parámetros: la lista de métodos que necesita llamar en el archivo DLL.
Nota: Debe utilizar el espacio de nombres System.Runtime.InteropServices en la declaración del programa.
DllImport solo se puede colocar en declaraciones de métodos.
El archivo DLL debe estar ubicado en el directorio actual del programa o en la ruta de consulta definida por el sistema (es decir, la ruta establecida por Path en la variable de entorno del sistema).
El tipo de variable de retorno, el nombre del método y la lista de parámetros deben ser coherentes con las definiciones del archivo DLL.
Si desea utilizar otros nombres de funciones, puede utilizar la configuración de la propiedad EntryPoint, como por ejemplo:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
Otros atributos opcionales de DllImportAttribute:
CharSet indica los caracteres utilizado en el conjunto de puntos de entrada, como: CharSet=CharSet.Ansi;
SetLastError indica si el método retiene el "último error" de Win32, como: SetLastError=true; ExactSpelling indica si el EntryPoint debe coincidir con el indicado. La ortografía del punto de entrada coincide exactamente, como por ejemplo: ExactSpelling=false;
PreserveSig indica si la firma del método debe conservarse o convertirse, como por ejemplo: PreserveSig=true.
CallingConvention indica la convención de llamadas del punto de entrada, como por ejemplo: CallingConvention=CallingConvention.Winapi;
Además, consulte otros artículos sobre "clasificación de datos" y "clasificación de números". y escalares lógicos".
Ejemplo de operación de C#:
1. Inicie VS.NET, cree un nuevo proyecto, el nombre del proyecto es "Tzb" y la plantilla es "Aplicación de Windows";
2. Haga doble clic en el elemento "Botón" en el elemento "Windows Forms" de la "Caja de herramientas" para agregar un botón al formulario "Form1";
3. : Nombre "B1", el texto es "Use DllImport para llamar a la DLL para que aparezca el cuadro de aviso", ajuste el botón B1 al tamaño apropiado y muévalo a la posición apropiada;
4. Haga doble clic en "Form1" en la vista de clases para abrir la vista de código "Form1 .cs", ingrese "using System.Runtime.InteropServices" encima de "namespace Tzb" para importar el espacio de nombres
5. -haga clic en el botón B1 de vista "Form1.cs [Diseño]", use las palabras clave estáticas y
extern para declarar el método "MsgBox" en el método "B1_Click" y adjunte el atributo DllImport al Método Aquí queremos utilizar la función "user32.dll" MessageBoxA", el código específico es el siguiente:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
Luego agregue el siguiente código en el cuerpo del método "B1_Click" para llamar al método "MsgBox" :
MsgBox(0, "¡Esto está usando DllImport para llamar al cuadro emergente de DLL!", "Challenge Cup", 0x30);
6. el programa y haga clic en el botón B1.
(2) Cargar y llamar dinámicamente funciones no administradas en DLL
Se ha explicado anteriormente cómo usar DllImport para llamar a funciones no administradas en DLL, pero esta es una función global. La función no administrada en la DLL tiene una variable estática S, la variable estática S se incrementará automáticamente en 1 cada vez que se llame a esta función. Como resultado, cuando se requiere un recuento, no se obtienen los resultados deseados.
A continuación se utilizarán ejemplos para ilustrar:
1. Creación de DLL
1) Inicie Visual C 6.0
2) Cree uno nuevo proyecto "Biblioteca de vínculos dinámicos Win32", el nombre del proyecto es "Count";
3) Seleccione "Un proyecto dll simple" en la interfaz de selección "Tipo de Dll"; p>
4) Abra Count.cpp y agregue el siguiente código:
// Función de exportación, use la llamada estándar " _stdcall "
extern "C" _declspec(dllexport) int _stdcall count(int init);
int _stdcall count(int init)
{//count función, utiliza el parámetro init para inicializar la variable entera estática S e incrementa S por 1 antes de devolver el valor
static int S=init;
S
return S;
5) Presione "F7" Compile y obtenga Count.dll (en la carpeta Debug bajo el directorio del proyecto).
2. Utilice DllImport para llamar a la función de recuento en la DLL.
1) Abra el proyecto "Tzb" y agregue un botón al formulario "Form1".
2) Cambie las propiedades del botón: el nombre es "B2", el texto es "Use DllImport para llamar a la función de conteo en la DLL", ajuste el botón B1 al tamaño apropiado y muévalo al posición adecuada.
3) Abra la vista de código "Form1.cs", use las palabras clave static y extern para declarar el método "count" y haga que tenga la implementación de la función exportada count de Count.dll, la El código es el siguiente:
p>
[DllImport("Count.dll")]
static extern int count(int init);
4) En la vista "Form1.cs [Diseño]", haga doble clic en el botón B2 y agregue el siguiente código en el cuerpo del método "B2_Click":
MessageBox.Show(" Utilice DllImport para llamar a la función de recuento en la DLL. El parámetro real n pasado es 0. El resultado es: " count(0).ToString(), "Challenge Cup");
MessageBox.Show(" Use DllImport para llamar al archivo. función count en la DLL. El parámetro real n pasado es 10 y el resultado es: " count(10).ToString() "n ¡El resultado no es 11 ", "Challenge Cup");
MessageBox.Show(" El resultado muestra: n Utilice DllImport ¡¡La llamada a funciones no administradas en la DLL es una función global y estática!! ", "Challenge Cup");
5) Copie Count.dll en la carpeta binDebug del proyecto "Tzb", presione "F5" para ejecutar el programa y haga clic en el botón B2, aparecerán los siguientes tres cuadros de aviso.
El primer cuadro de mensaje muestra el resultado de llamar a "count(0)", y el segundo cuadro de mensaje muestra el resultado de llamar a "count(10)". Los resultados obtenidos pueden demostrar que "usar llamadas DllImport". funciones no administradas en la DLL como funciones globales y estáticas". Por lo tanto, a veces nuestro propósito no se puede lograr, por lo que debemos utilizar el método que se presenta a continuación: C# llama dinámicamente a funciones en DLL.
3. C# llama dinámicamente funciones en DLL
Debido a que DllImport en C# no se puede usar como un ensamblaje de carga/descarga dinámica, solo puede usar funciones API. En kernel32.dll, las funciones relacionadas con las llamadas a bibliotecas dinámicas incluyen [3]:
1) LoadLibrary (o AfxLoadLibrary de MFC), que carga la biblioteca dinámica
2) GetProcAddress, Get; la función que se introducirá y convertirá el nombre del símbolo o el número de identificación en la dirección interna de la DLL;
3) FreeLibrary (o AfxFreeLibrary de MFC), libera la biblioteca de enlaces dinámicos.
Sus prototipos son:
HMODULE LoadLibrary(LPCTSTR lpFileName);
FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
BOOL FreeLibrary(HMODULE hModule);
Ahora, podemos usar IntPtr hModule=LoadLibrary("Count.dll"); para obtener el identificador de Dll, use IntPtr farProc=GetProcAddress(hModule,"_count@4 " ); para obtener la dirección de entrada de la función.
Sin embargo, después de conocer la dirección de entrada de la función, ¿cómo llamar a esta función? Debido a que no hay un puntero de función en C#, no existe un método de llamada de puntero de función para llamar a funciones como C#, por lo que tenemos que recurrir a otros métodos. Después de investigar, descubrimos que podemos lograr nuestros objetivos combinando las clases y funciones en System.Reflection.Emit y System.Reflection.Assembly. Para mayor comodidad y reutilización del código en el futuro, podemos escribir una clase.
1. Abra el proyecto "Tzb", abra la vista de clases, haga clic derecho en "Tzb", seleccione "Agregar" --> "Clase", establezca el nombre de la clase en "dld", es decir. , el dll de carga dinámica La primera letra de cada palabra
2. Agregue el espacio de nombres requerido y declare la enumeración del método de transferencia de parámetros:
usando System.Runtime.InteropServices // Usar; DllImport requiere este espacio de nombres
usando System.Reflection; // Este espacio de nombres es necesario para usar la clase Assembly
usando System.Reflection.Emit // Este espacio de nombres es necesario para usar ILGenerator;
p>Agregue el siguiente código encima de "dld de clase pública" para declarar la enumeración del método de transferencia de parámetros:
/// resumengt; / Enumeración del método de transferencia de parámetros Por ejemplo, ByValue significa transferencia de valor, ByRef significa transferencia de dirección
/// lt;/summarygt;
public enum ModePass
{
ByValue = 0x0001,
ByRef = 0x0002
}
3. Declare LoadLibrary, GetProcAddress, FreeLibrary y las variables privadas hModule y farProc. :
/// lt; resumengt;
/// El prototipo es: HMODULE LoadLibrary(LPCTSTR lpFileName); ;
/// lt;param name="lpFileName"gt;nombre del archivo DLLlt;/paramgt;
/// lt;returnsgt;El identificador del módulo de biblioteca de funcioneslt; /returnsgt;
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
/// resumengt;
/// El prototipo es: FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
/// lt /summarygt; ; param name="hModule"gt; Contiene el identificador del módulo de biblioteca de funciones que se llamará lt; / paramgt;
/// param name="lpProcName"gt; función lt; / paramgt;
/// lt;
Función pointerlt;/returnsgt;
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/ // lt; resumengt;
/// El prototipo es: BOOL FreeLibrary(HMODULE hModule);
/// lt /summarygt; // lt; param name="hModule"gt; el identificador del módulo de biblioteca de funciones que se publicará lt; / paramgt;
/// lt; / devuelve gt;
[DllImport("kernel32", EntryPoint="FreeLibrary", SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
/// lt;summarygt;
/// El identificador del módulo de biblioteca de funciones devuelto por Loadlibrary
/// lt;/summarygt;
private IntPtr hModule=IntPtr. Zero;
/// lt; resumengt;
/// El puntero de función devuelto por GetProcAddress
/// lt ;/summarygt;
private IntPtr farProc=IntPtr.Zero;
4. Agregue el método LoadDll y sobrecargue este método para mayor comodidad al llamar:
/ // lt; resumengt;
/// Cargar Dll
/// lt /summarygt;
/// param nombre="lpFileName" "gt; nombre del archivo DLL lt;/paramgt;
public void LoadDll(string lpFileName)
{
hModule=LoadLibrary(lpFileName);
if( hModule==IntPtr.Zero)
throw(new Exception(" No encontrado: " lpFileName "." ));
}
Si ya existe Para cargar el identificador de la Dll, puede utilizar la segunda versión del método LoadDll:
public void LoadDll(IntPtr HMODULE)
{
if(HMODULE==IntPtr.Zero)
throw(new Exception("El identificador HMODULE del módulo de biblioteca de funciones pasado está vacío." ));
hModule=HMODULE;
}
5. Agregue el método LoadFun y sobrecargue este método para mayor comodidad al llamar. El código específico y los comentarios del método son los siguientes:
/// lt; resumengt;
/// Obtener puntero de función
/// lt /summarygt; // lt; param name="lpProcName"gt; el nombre de la función que llama lt; / paramgt;
public void LoadFun(string lpProcName)
{ // Si la función módulo de biblioteca Si el identificador está vacío, se generará una excepción
if(hModule==IntPtr.Zero)
throw(new Exception("El identificador del módulo de biblioteca de funciones es vacío, asegúrese de que la operación LoadDll!"));
// Obtener puntero de función
farProc = GetProcAddress(hModule, lpProcName);
// Si puntero de función, lanzar excepción
if(farProc==IntPtr.Zero)
throw(new Exception("No encontrado: " lpProcName "El punto de entrada de esta función"));
}
/// lt; resumengt;
/// Obtener puntero de función
/// lt /summarygt;
/// lt; param name="lpFileName"gt; Contiene el nombre del archivo DLL que necesita llamar a la función lt /paramgt; param name="lpProcName"gt; Llame a la función namelt;/paramgt;
public void LoadFun(string lpFileName, string lpProcName)
{ // Obtener el identificador de la biblioteca de funciones module
hModule=LoadLibrary (lpFileName);
// Si el identificador del módulo de la biblioteca de funciones está vacío, se lanzará una excepción
if(hModule ==IntPtr.Zero)
lanzar (nueva E
xception("No encontrado: " lpFileName "." ));
// Obtener puntero de función
farProc = GetProcAddress(hModule, lpProcName
); / Si es un puntero de función, lanza una excepción
if(farProc==IntPtr.Zero)
throw(new Exception(" No encontrado: " lpProcName "El punto de entrada de esta función" ));
}
6. Agregue los métodos UnLoadDll e Invoke, y el método Invoke también está sobrecargado:
/// lt; resumengt ;
p>/// Descargar Dll
/// lt;/summarygt;
public void UnLoadDll()
{
FreeLibrary(hModule);
hModule=IntPtr.Zero;
farProc=IntPtr.Zero;
}