Résumé de l'utilisation de DllImport en C #

(tour)

J'ai récemment utilisé DllImport et j'ai découvert que la plupart du contenu de Baidu sur Internet est le même, et je l'ai récupéré sur MSDN. Je vais maintenant résumer le contenu et le partager avec vous.

 

Lorsque vous étudiez C # dans un travail réel , vous pouvez vous demander: Pourquoi devons-nous réécrire le code de certaines fonctions existantes (telles que certaines fonctions sous Windows, certaines méthodes déjà écrites en C ++), existe- t - il un moyen d' écrire directement C #? vous utilisez ces fonctions qui existent déjà? La réponse est oui, vous pouvez appeler directement ces fonctions via DllImport en C #.
DllImport est une classe d'attribut sous l'espace de noms System.Runtime.InteropServices, donc si vous souhaitez utiliser DllImport dans ASP.NET, vous devez d'abord "utiliser System.Runtime.InteropServices;". Sa fonction est de fournir les informations nécessaires pour appeler des fonctions dérivées de DLL non gérées. L'attribut DllImport est appliqué à la méthode et nécessite au moins le nom de la dll contenant le point d'entrée. Définition de l'attribut DllImport

comme suit:
espace de noms System.Runtime.InteropServices
   {
  
  
    [AttributeUsage (AttributeTargets.Method)]
    classe publique DllImportAttribute: System.Attribute
    {
  
  

 

 

public DllImportAttribute (string dllName) {...} // Le paramètre de positionnement est dllName
public CallingConvention CallingConvention; // Convention d'appel du point d'entrée
public CharSet CharSet; // Connexion de caractères utilisée par le point d'entrée
chaîne publique EntryPoint; // Nom du point d'entrée
public bool ExactSpelling; // Si l'orthographe doit être exactement la même que le point d'entrée indiqué, la valeur par défaut est false
public bool PreserveSig; // La signature de la méthode est-elle conservée ou convertie
public bool SetLastError; // La valeur de retour de la méthode FindLastError est stockée ici
chaîne publique Valeur {get {...}}                            

 

 

    } 
}
La description:
1. DllImport ne peut être placé que sur les déclarations de méthode.
2. DllImport a un seul paramètre de positionnement: spécifiez le paramètre dllName qui contient le nom dll de la méthode importée.
3. DllImport a cinq paramètres nommés:
   a. Le paramètre CallingConvention indique la convention d'appel du point d'entrée. Si CallingConvention n'est pas spécifié, la valeur par défaut CallingConvention.Winapi est utilisée.
   b. Le paramètre CharSet spécifie le jeu de caractères utilisé au point d'entrée. Si CharSet n'est pas spécifié, la valeur par défaut CharSet.Auto est utilisée.
   c. Le paramètre EntryPoint donne le nom du point d'entrée dans la DLL. Si EntryPoint n'est pas spécifié, le nom de la méthode elle-même est utilisé.
   d. Le paramètre ExactSpelling indique si EntryPoint doit correspondre exactement à l'orthographe du point d'entrée indiqué. Si ExactSpelling n'est pas spécifié, la valeur par défaut false est utilisée.
   e. Le paramètre PreserveSig indique si la signature de la méthode est conservée ou convertie. Lorsque la signature est convertie, elle est convertie en signature avec une valeur de retour HRESULT et un paramètre de sortie supplémentaire nommé retval avec la valeur de retour. Si PreserveSig n'est pas spécifié, la valeur par défaut true est utilisée.
   f. Le paramètre SetLastError indique si la méthode conserve la "dernière erreur" Win32. Si SetLastError n'est pas spécifié, la valeur par défaut false est utilisée.
4. Il s'agit d'une classe d'attributs à usage unique.
5. La méthode modifiée avec l'attribut DllImport doit avoir le modificateur extern.
Exemple d'utilisation de DllImport (un win32api utilisé pour écrire des fichiers ini):
 DllImport ("kernel32")
 privé statique externe long WritePrivateProfileString (section de chaîne, clé de chaîne, valeur de chaîne, chaîne filePath);
Le type de données de l'appel de WinAPI avec cette méthode correspond à: DWORD = int ou uint, BOOL = bool, constante prédéfinie = enum, structure = struct.

 

Problème de chemin DllImport:

 

DllImport trouvera automatiquement les lieux dans l'ordre: 
1. Le répertoire où se trouve l'exe 
2. Répertoire System32 
3. Répertoire des variables d'environnement

Il vous suffit donc de copier la DLL référencée dans ces trois répertoires et vous n'avez pas besoin d'écrire le chemin.

 

 

Sur le web, mais aussi dans l'application
Plus tard, il a été découvert que l'utilisation de [DllImport (@ "C: \ OJ \ Bin \ Judge.dll")] pour spécifier le chemin absolu de la DLL peut être chargée normalement.
Ce problème se produit le plus souvent lors de l'utilisation de composants DLL non gérés tiers. Le mien est également le problème pour le moment. La solution officielle d'Asp.Net Team est la suivante:
Tout d'abord, vous devez confirmer les composants auxquels vous faites référence, ceux qui sont gérés et ceux qui ne le sont pas. Managed est facile à gérer, les composants utilisés directement doivent être cités et les composants utilisés indirectement doivent être copiés dans le répertoire bin. Le traitement non géré sera plus gênant. En fait, vous copiez dans bin n'aidera pas, car le CLR copiera les fichiers dans un répertoire temporaire, puis y exécutera le Web, et le CLR ne copiera que les fichiers gérés, c'est pourquoi nous mettons clairement les dll non gérées dans Il indique toujours que le module ne peut pas être chargé sous le bac.
L'approche spécifique est la suivante:
Tout d'abord, nous pouvons trouver une place sur le serveur pour créer un nouveau répertoire, s'il s'agit de C: \ DLL;
Ensuite, dans la variable d'environnement, ajoutez ce répertoire à la variable Path;
Enfin, copiez tous les fichiers non gérés dans C: \ DLL, ou plus simplement placez la DLL dans le répertoire system32.
Pour les applications qui peuvent être déployées par elles-mêmes, une telle exception n'est pas une solution. Cependant, si nous utilisons l'espace virtuel, nous ne pouvons pas enregistrer la variable PATH ou copier notre propre DLL dans le répertoire system32. Dans le même temps, nous ne connaissons pas forcément le chemin physique de notre DLL.
Seules les constantes de chaîne peuvent être utilisées dans DllImport et Server.MapPath (@ "~ / Bin / Judge.dll") ne peut pas être utilisé pour déterminer le chemin d'accès physique.
 
Le problème de la vitesse de chargement lente de DllImport:
Cependant, j'ai trouvé qu'appeler cette "Dll ​​non gérée" est assez lent, peut-être parce que ma méthode nécessite une authentification à distance, mais elle est trop lente. Après de nombreuses recherches, j'ai finalement trouvé une solution parfaite.
Nous utilisons d'abord
[DllImport ("kernel32.dll")]
private extern statique IntPtr LoadLibrary (chemin de chaîne);
[DllImport ("kernel32.dll")]
private extern statique IntPtr GetProcAddress (IntPtr lib, String funcName);
[DllImport ("kernel32.dll")]
private extern static bool FreeLibrary (IntPtr lib);
Les adresses des fonctions LoadLibrary et GetProcAddress sont obtenues respectivement, puis les fonctions de notre DLL sont obtenues via ces deux fonctions.
Nous pouvons d'abord utiliser Server.MapPath (@ "~ / Bin / Judge.dll") pour obtenir le chemin physique de notre DLL, puis utiliser LoadLibrary pour charger, et enfin utiliser GetProcAddress pour obtenir l'adresse de la fonction à utiliser.
Le code de classe personnalisé suivant termine le chargement et l'appel de fonction de LoadLibrary:
classe publique DllInvoke
    {
  
  
 
        [DllImport ("kernel32.dll")]
        private extern statique IntPtr LoadLibrary (chemin de chaîne);
        [DllImport ("kernel32.dll")]
        private extern statique IntPtr GetProcAddress (IntPtr lib, String funcName);
        [DllImport ("kernel32.dll")]
        private extern statique bool FreeLibrary (IntPtr lib);
        private IntPtr hLib;
        public DllInvoke (chaîne DLLPath)
        {
  
  
            hLib = LoadLibrary (DLLPath);
        }
        ~ DllInvoke ()
        {
  
  
            FreeLibrary (hLib);          
        }
        // Convertit la fonction à exécuter en délégué
        Appel du délégué public (chaîne APIName, type t)
        {
  
  
            IntPtr api = GetProcAddress (hLib, APIName);
            return (Délégué) Marshal.GetDelegateForFunctionPointer (api, t);
        }
}
Le code suivant effectue l'appel
délégué public int Compile (commande String, StringBuilder inf); // 编译
DllInvoke dll = new DllInvoke (Server.MapPath (@ "~ / Bin / Judge.dll"));
Compile compile = (Compile) dll.Invoke ("Compile", typeof (Compile));
StringBuilder inf;
compile (@ "gcc ac -o a.exe", inf); // voici pour appeler la fonction Compile définie dans ma DLL
 
Exemple d'utilisation de DllImport:
Bibliothèque utilisée dans une programmation Win32 C #
  utilisée de type correspondant:
1. DWORD est un entier de 4 octets, nous pouvons donc utiliser int ou uint comme type correspondant C #.
2. Le type booléen correspond à BOOL.
Exemple 1 : Appelez l'API Beep () pour émettre un son
Beep () est défini dans kernel32.lib. Tel que défini dans MSDN, Beep a le prototype suivant:
BOOL Beep (DWORD dwFreq, // fréquence sonore
          DWORD dwDuration // durée du son); 
Écrivez le prototype suivant en C #:
[DllImport ("kernel32.dll")] 
public static extern bool Bip (fréquence int, durée int);
Exemple 2 : types énumérés et constantes
MessageBeep () est défini dans user32.lib. Tel que défini dans MSDN, MessageBeep possède le prototype suivant:
BOOL MessageBeep (UINT uType // type de son
                  ); 
Écrivez le prototype en C #:
public enum BeepType
{
  
  
   SimpleBeep = -1,
   IconAsterisk = 0x00000040,
   IconExclamation = 0x00000030,
   IconHand = 0x00000010,
   IconQuestion = 0x00000020,
   Ok = 0x00000000,
}
Le paramètre uType accepte en fait un ensemble de constantes prédéfinies. Pour le paramètre uType, il est logique d'utiliser le type enum.
[DllImport ("user32.dll")]
public static extern boolMessageBeep (BeepType beepType);
Exemple 3 : structure de traitement
Parfois, j'ai besoin de déterminer l'état de la batterie de mon ordinateur portable. Win32 fournit des fonctions de gestion de l'alimentation à cet effet. Recherchez dans MSDN la fonction GetSystemPowerStatus ().
BOOL GetSystemPowerStatus (LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
Cette fonction contient un pointeur vers une structure, dont nous n'avons pas encore traité. Pour gérer la structure, nous devons définir la structure en C #. Nous commençons par la définition de non managé:
typedef struct _SYSTEM_POWER_STATUS {
  
  
   BYTE ACLineStatus;
   BYTE BatteryFlag;
   BYTE BatteryLifePercent;
   BYTE Reserved1;
   DWORD BatteryLifeTime;
   DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, * LPSYSTEM_POWER_STATUS;
Ensuite, obtenez la version C # en remplaçant les types C # par les types C.
struct SystemPowerStatus
{
  
  
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  octet réservé1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}
    De cette façon, vous pouvez facilement écrire un prototype C #:
    [DllImport ("kernel32.dll")]
    public static extern bool GetSystemPowerStatus (réf SystemPowerStatus systemPowerStatus);
Dans ce prototype, nous utilisons "ref" pour indiquer que le pointeur de structure sera passé à la place de la valeur de structure. C'est la manière générale de traiter les structures transmises par des pointeurs.
Cette fonction fonctionne bien, mais il est préférable de définir les champs ACLineStatus et batteryFlag comme enum:
enum ACLineStatus: octet
{
  
  
   Hors ligne = 0,
   En ligne = 1,
   Inconnu = 255,
}
enum BatteryFlag: byte
{
  
  
   Élevé = 1,
   Faible = 2,
   Critique = 4,
   Charge = 8,
   NoSystemBattery = 128,
   Inconnu = 255,
}
Veuillez noter que puisque les champs de la structure sont des octets, nous utilisons byte comme type de base de l'énumération.
Appel de code C ++ en C #
type int
[DllImport ("MyDLL.dll")] 
public static extern int mySum (int a1, int b1); // retourne un type int
extern «C» __declspec (dllexport) int WINAPI mySum (int a2, int b2) // Déclaré dans la DLL
{ 
    // a2 b2 ne peut pas changer a1 b1
    // a2 = ..
    // b2 = ...
 retourne a + b;
}
// Transfert de paramètre int type public static extern int mySum (ref int a1, ref int b1); // Déclarer extern "C" dans la DLL __declspec (dllexport) int WINAPI mySum (int * a2, int * b2) {// Oui Modifier a1, b1 * a2 = ... * b2 = ... return a + b;}

La DLL doit passer char * type  [DllImport ("MyDLL.dll")] // Passer en valeur public static extern int mySum (string astr1, string bstr1); // Declare extern "C" in DLL __declspec (dllexport) int WINAPI mySum (char * astr2, char * bstr2) {// Changer astr2bstr 2, astr1 bstr1 ne sera pas changé return a + b;}

La DLL doit envoyer char * type [DllImport ("MyDLL.dll")] // la valeur envoyée public static extern int mySum (StringBuilder abuf, StringBuilder bbuf); // Déclarer extern "C" dans la DLL __declspec (dllexport ) int WINAPI mySum (char * astr, char * bstr) {// sortant char * change astr bstr -> abuf, bbuf peut être changé return a + b;} Fonction de rappel DLL BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARAM lParam)

usingSystem; 
using System.Runtime.InteropServices; 
délégué public bool CallBack (int hwnd, int lParam); // Classe 
publique EnumReportApp 
{ 
   [DllImport ("user32")] 
   public static extern int EnumWindows (CallBack x, int y); 
   public static void Main ()
   { 
     CallBack myCallBack = nouveau CallBack (EnumReportApp.Report);
     EnumWindows (myCallBack, 0); 
   } 
   Rapport booléen statique public (int hwnd, int lParam) 
   { 
      Console.Write ("Le handle de fenêtre est"); 
      Console.WriteLine (hwnd); retourne vrai; 
   } 
}

DLL 传递 结构 BOOL PtInRect (const RECT * lprc, POINT pt); using System.Runtime.InteropServices; [StructLayout (LayoutKind.Sequential)] structure publique 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)] public int right; [FieldOffset (12)] public int bottom; } Classe XXXX

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

Je suppose que tu aimes

Origine blog.csdn.net/u014780302/article/details/100740111
conseillé
Classement