


Explication détaillée de la solution pour C# appelant C++DLL pour transmettre un tableau de structure
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); } }
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; };
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); } }
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)
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
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!

Outils d'IA chauds

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

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

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

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

Sujets chauds

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.

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.

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.

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.

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.

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.

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.

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.
