Comment puis-je transmettre des données MemoryStream à une DLL C ++ non gérée à l'aide de P / Invoke
-
20-08-2019 - |
Question
J'ai besoin de votre aide pour le scénario suivant:
Je lis des données matérielles dans un MemoryStream (C #) et j’ai besoin de les transmettre en mémoire à une dll implémentée en C ++ non géré (à l’aide du pointeur ??). Les données lues (dans le flux) sont très volumineuses (mégaoctets). Je comprends que je peux P / Invoke cette dll mais ce que je ne suis pas sûr, c'est comment passer le pointeur / référence des données du flux à l'API C ++?
Je dois admettre que je suis confus, car je suis novice en C #. Dois-je utiliser unsafe / fixed du fait que les données sont volumineuses ou qu'elles ne sont pas pertinentes étant donné que l'objet MemoryStream est géré par le GC? Quelques exemples de code / description détaillée seraient très utiles. Merci
Signature de l'API non gérée:
BOOL doQuelque chose (void * rawData, int dataLength)
La solution
Si vous n'attendez que des octets, vous pouvez lire le MemoryStream dans un tableau d'octets, puis lui transmettre un pointeur sur la méthode.
Vous devez déclarer la méthode externe:
[DllImport("mylibrary.dll", CharSet = CharSet.Auto)]
public static extern bool doSomething(IntPtr rawData, int dataLength);
Ensuite, lisez les octets du MemoryStream dans un tableau d'octets. Allouer un GCHandle qui:
Une fois alloué, vous pouvez utiliser une GCHandle pour empêcher l'objet géré de être ramassé à la poubelle collecteur lorsqu'un client non géré détient la seule référence. Sans une telle une poignée, l'objet peut être collecté par le ramasse-miettes avant achève ses travaux au nom du client non géré.
Enfin, utilisez la méthode AddrOfPinnedObject pour obtenir un IntPtr à transmettre à la dll C ++.
private void CallTheMethod(MemoryStream memStream)
{
byte[] rawData = new byte[memStream.Length];
memStream.Read(rawData, 0, memStream.Length);
GCHandle rawDataHandle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject ();
doSomething(address, rawData.Length);
rawDataHandle.Free();
}