Maison développement back-end Tutoriel C#.Net Explication détaillée de la solution pour C# appelant C++DLL pour transmettre un tableau de structure

Explication détaillée de la solution pour C# appelant C++DLL pour transmettre un tableau de structure

Mar 28, 2017 am 11:52 AM

Cet article présente principalement des informations pertinentes sur la solution ultime pour que C# appelle C++DLL pour transmettre le tableau de structure. Les amis dans le besoin peuvent se référer à

C# pour appeler C++DLL pour transmettre. structure La solution ultime pour les tableaux de corps

Lors du développement d'un projet, vous devez appeler une DLL encapsulée en C++. Les types courants correspondent généralement à C#. Utilisez simplement DllImport pour introduire la fonction à partir de la DLL. C'est tout. Mais lorsqu'une structure, un tableau de structures ou un pointeur de structure est transmis, vous constaterez qu'il n'y a pas de type correspondant en C#. Que faire à ce moment-là ? La première réaction est que C# définit également la structure et la transmet ensuite en paramètre. Cependant, lorsque nous définissons une structure et que nous voulons y transmettre des paramètres, une exception sera levée, ou la structure sera transmise, mais la valeur de retour n'est pas celle que nous voulons. Après le débogage suivi, nous. J'ai constaté que ces valeurs n'ont pas changé du tout, le code est le suivant.

[DllImport("workStation.dll")] 
    private static extern bool fetchInfos(Info[] infos); 
    public struct Info 
    { 
      public int OrderNO; 
 
      public byte[] UniqueCode; 
 
      public float CpuPercent;          
 
    }; 
    private void buttonTest_Click(object sender, EventArgs e) 
    { 
      try 
      { 
      Info[] infos=new Info[128]; 
        if (fetchInfos(infos)) 
        { 
          MessageBox.Show("Fail"); 
        } 
      else 
      { 
          string message = ""; 
          foreach (Info info in infos) 
          { 
            message += string.Format("OrderNO={0}\r\nUniqueCode={1}\r\nCpu={2}", 
                       info.OrderNO, 
                       Encoding.UTF8.GetString(info.UniqueCode), 
                       info.CpuPercent 
                       ); 
          } 
          MessageBox.Show(message); 
      } 
      } 
      catch (System.Exception ex) 
      { 
        MessageBox.Show(ex.Message); 
      } 
    }
Copier après la connexion

Plus tard, après avoir recherché des informations, il y a eu un article mentionnant que C# est une mémoire gérée. Maintenant, le tableau de structure doit être transmis, qui est attribut mémoire non gérée, qui doit être transmis. être précisé avec un espace Marsh avant de passer. Modifiez donc la structure comme suit.

StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
   public struct Info 
   { 
     public int OrderNO; 
 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
     public byte[] UniqueCode; 
 
     public float CpuPercent;          
 
   };
Copier après la connexion

Cependant, après de telles améliorations, les résultats de course ne sont toujours pas idéaux et les valeurs sont soit fausses, soit inchangées. Quelle en est la raison ? Après avoir constamment recherché des informations, j'ai finalement trouvé un article qui mentionnait le transfert de structures. Certaines peuvent être effectuées comme ci-dessus, mais d'autres ne le peuvent pas, surtout lorsque le paramètre est un pointeur de structure ou un pointeur de tableau de structures en C++. être utilisé pour correspondre à l'endroit où C# est appelé, et le code suivant sera amélioré ultérieurement.

[DllImport("workStation.dll")] 
  private static extern bool fetchInfos(IntPtr infosIntPtr); 
  [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
  public struct Info 
  { 
    public int OrderNO; 
 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    public byte[] UniqueCode; 
 
    public float CpuPercent; 
 
  }; 
  private void buttonTest_Click(object sender, EventArgs e) 
  { 
    try 
    { 
      int workStationCount = 128; 
      int size = Marshal.SizeOf(typeof(Info)); 
      IntPtr infosIntptr = Marshal.AllocHGlobal(size * workStationCount); 
      Info[] infos = new Info[workStationCount]; 
      if (fetchInfos(infosIntptr)) 
      { 
        MessageBox.Show("Fail"); 
        return; 
      } 
      for (int inkIndex = 0; inkIndex < workStationCount; inkIndex++) 
      { 
        IntPtr ptr = (IntPtr)((UInt32)infosIntptr + inkIndex * size); 
        infos[inkIndex] = (Info)Marshal.PtrToStructure(ptr, typeof(Info)); 
      } 
 
      Marshal.FreeHGlobal(infosIntptr); 
 
      string message = ""; 
      foreach (Info info in infos) 
      { 
        message += string.Format("OrderNO={0}\r\nUniqueCode={1}\r\nCpu={2}", 
                    info.OrderNO, 
                    Encoding.UTF8.GetString(info.UniqueCode), 
                    info.CpuPercent 
                    ); 
      } 
      MessageBox.Show(message); 
 
    } 
    catch (System.Exception ex) 
    { 
      MessageBox.Show(ex.Message); 
    } 
  }
Copier après la connexion

Il est à noter qu'à ce moment, l'interface a été modifiée en IntPtr. Grâce à la méthode ci-dessus, le tableau de structure est finalement transmis. Cependant, une chose à noter ici est que différents compilateurs ne seront pas sûrs de la taille de la structure. Par exemple, si la structure ci-dessus

n'est pas alignée en octets dans BCB, elle sera parfois plus grande. que la structure normale. La taille du corps est de 2 octets de plus. Parce que BCB utilise par défaut un tri sur 2 octets et VC utilise par défaut un tri sur 1 octet. Pour résoudre ce problème, ajoutez l'alignement des octets à la structure BCB ou ouvrez deux octets supplémentaires (s'il y en a plus) en C#. Le code d'alignement d'octets est le suivant.

#pragma pack(push,1) 
  struct Info 
{ 
  int OrderNO; 
       
  char UniqueCode[32]; 
 
  float CpuPercent; 
}; 
#pragma pack(pop)
Copier après la connexion

Utilisez Marsh.AllocHGlobal pour ouvrir de l'espace mémoire pour les pointeurs de structure. Le but est de le convertir en mémoire non gérée. Donc, si Marsh.AllocHGlobal n'est pas utilisé, existe-t-il un autre moyen ?

En fait, qu'il s'agisse d'un pointeur ou d'un tableau en C++, il est finalement stocké en mémoire un par un. Autrement dit, il est finalement affiché sous la forme d'un one-. tableau d'octets dimensionnel, donc si nous ouvrons un tableau unidimensionnel de taille égale, est-ce que ça va ? La réponse est oui, la mise en œuvre est donnée ci-dessous.

[DllImport("workStation.dll")] 
    private static extern bool fetchInfos(IntPtr infosIntPtr); 
    [DllImport("workStation.dll")] 
    private static extern bool fetchInfos(byte[] infos); 
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
    public struct Info 
    { 
      public int OrderNO; 
 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
      public byte[] UniqueCode; 
 
      public float CpuPercent; 
 
    }; 
 
   
    private void buttonTest_Click(object sender, EventArgs e) 
    { 
      try 
      { 
        int count = 128; 
        int size = Marshal.SizeOf(typeof(Info)); 
        byte[] inkInfosBytes = new byte[count * size];         
        if (fetchInfos(inkInfosBytes)) 
        { 
          MessageBox.Show("Fail"); 
          return; 
        } 
        Info[] infos = new Info[count]; 
        for (int inkIndex = 0; inkIndex < count; inkIndex++) 
        { 
          byte[] inkInfoBytes = new byte[size]; 
          Array.Copy(inkInfosBytes, inkIndex * size, inkInfoBytes, 0, size); 
          infos[inkIndex] = (Info)bytesToStruct(inkInfoBytes, typeof(Info)); 
        } 
 
        string message = ""; 
        foreach (Info info in infos) 
        { 
          message += string.Format("OrderNO={0}\r\nUniqueCode={1}\r\nCpu={2}", 
                      info.OrderNO, 
                      Encoding.UTF8.GetString(info.UniqueCode), 
                      info.CpuPercent 
                      ); 
        } 
        MessageBox.Show(message); 
 
      } 
      catch (System.Exception ex) 
      { 
        MessageBox.Show(ex.Message); 
      } 
    } 
 
    #region bytesToStruct 
    /// <summary> 
    /// Byte array to struct or classs. 
    /// </summary> 
    /// <param name=”bytes”>Byte array</param> 
    /// <param name=”type”>Struct type or class type. 
    /// Egg:class Human{...}; 
    /// Human human=new Human(); 
    /// Type type=human.GetType();</param> 
    /// <returns>Destination struct or class.</returns> 
    public static object bytesToStruct(byte[] bytes, Type type) 
    { 
 
      int size = Marshal.SizeOf(type);//Get size of the struct or class.      
      if (bytes.Length < size) 
      { 
        return null; 
      } 
      IntPtr structPtr = Marshal.AllocHGlobal(size);//Allocate memory space of the struct or class.  
      Marshal.Copy(bytes, 0, structPtr, size);//Copy byte array to the memory space. 
      object obj = Marshal.PtrToStructure(structPtr, type);//Convert memory space to destination struct or class.      
      Marshal.FreeHGlobal(structPtr);//Release memory space.   
      return obj; 
    } 
    #endregion
Copier après la connexion

Lorsque vous ne savez vraiment pas comment transmettre des données, vous pouvez envisager de les transmettre sous forme de tableau d'octets (même un entier suffit, à condition qu'il ouvre 4 octets (sous 32 bits )), tant qu'il est ouvert. Correspondant à la longueur, après avoir obtenu les données, elles doivent être converties en données requises selon les règles de type. Généralement, l'objectif peut être atteint.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Active Directory avec C# Active Directory avec C# Sep 03, 2024 pm 03:33 PM

Guide d'Active Directory avec C#. Nous discutons ici de l'introduction et du fonctionnement d'Active Directory en C# ainsi que de la syntaxe et de l'exemple.

Générateur de nombres aléatoires en C# Générateur de nombres aléatoires en C# Sep 03, 2024 pm 03:34 PM

Guide du générateur de nombres aléatoires en C#. Nous discutons ici du fonctionnement du générateur de nombres aléatoires, du concept de nombres pseudo-aléatoires et sécurisés.

Modificateurs d'accès en C# Modificateurs d'accès en C# Sep 03, 2024 pm 03:24 PM

Guide des modificateurs d'accès en C#. Nous avons discuté de l'introduction Types de modificateurs d'accès en C# ainsi que d'exemples et de résultats.

Vue Grille de données C# Vue Grille de données C# Sep 03, 2024 pm 03:32 PM

Guide de la vue Grille de données C#. Nous discutons ici des exemples de la façon dont une vue de grille de données peut être chargée et exportée à partir de la base de données SQL ou d'un fichier Excel.

Sérialisation C# Sérialisation C# Sep 03, 2024 pm 03:30 PM

Guide de sérialisation C#. Nous discutons ici de l'introduction, des étapes de l'objet de sérialisation C#, du fonctionnement et de l'exemple respectivement.

Modèles en C# Modèles en C# Sep 03, 2024 pm 03:33 PM

Guide des modèles en C#. Nous discutons ici de l'introduction et des 3 principaux types de modèles en C# ainsi que de ses exemples et de l'implémentation du code.

Nombres premiers en C# Nombres premiers en C# Sep 03, 2024 pm 03:35 PM

Guide des nombres premiers en C#. Nous discutons ici de l'introduction et des exemples de nombres premiers en c# ainsi que de l'implémentation du code.

Services Web en C# Services Web en C# Sep 03, 2024 pm 03:32 PM

Guide des services Web en C#. Nous discutons ici d'une introduction aux services Web en C# avec l'utilisation de la technologie, ses limitations et des exemples.

See all articles