2008-11-05 10 views
2

J'appelle une DLL C++ non gérée qui attend un char * comme l'un de ses paramètres et je veux y insérer un octet []. Le projet est écrit en VB.NET.vb.net byte [] en C++ char *

Quel type de triage fonctionnera pour cela?

Répondre

0

Je ne suis pas un expert .net, mais j'ai dû faire quelque chose de similaire récemment.

Il est non seulement une question de sérialisation, vous devez également arrêter le collecteur d'ordures de nettoyage de votre tableau d'octets alors qu'il est utilisé en C++ terre ...

L'extrait ci-dessous de C# devrait aider.

// pin the byte[] (byteArray) 
GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); 
IntPtr address = handle.AddrOfPinnedObject(); 
// Do your C++ stuff, using the address pointer. 

// Cleanup 
handle.Free();
1

Si vous devez épingler une structure gérée pour la passer en paramètre, vous pouvez utiliser le code suivant.

// (c) 2007 Marc Clifton 
    /// <summary> 
    /// A helper class for pinning a managed structure so that it is suitable for 
    /// unmanaged calls. A pinned object will not be collected and will not be moved 
    /// by the GC until explicitly freed. 
    /// </summary> 

    internal class PinnedObject<T> : IDisposable where T : struct 
    { 
     protected T managedObject; 
     protected GCHandle handle; 
     protected IntPtr ptr; 
     protected bool disposed; 

     public T ManangedObject 
     { 
      get 
      { 
       return (T)handle.Target; 
      } 
      set 
      { 
       Marshal.StructureToPtr(value, ptr, false); 
      } 
     } 

     public IntPtr Pointer 
     { 
      get { return ptr; } 
     } 

     public int Size 
     { 
      get { return Marshal.SizeOf(managedObject); } 
     } 

     public PinnedObject() 
     { 
      managedObject = new T(); 
      handle = GCHandle.Alloc(managedObject, GCHandleType.Pinned); 
      ptr = handle.AddrOfPinnedObject(); 
     } 

     ~PinnedObject() 
     { 
      Dispose(); 
     } 

     public void Dispose() 
     { 
      if (!disposed) 
      { 
       if (handle.IsAllocated) 
        handle.Free(); 
       ptr = IntPtr.Zero; 
       disposed = true; 
      } 
     } 
    } 
} 

Vous pouvez ensuite appeler le code non géré à l'aide de PinnedObject.Pointer. Dans votre déclaration extern, utilisez IntPtr comme type pour ce paramètre.

PinnedObject<BatteryQueryInformation> pinBatteryQueryInfo = new PinnedObject<BatteryQueryInformation>(); 
pinBatteryQueryInfo.ManangedObject = _structBatteryQueryInfo; 
Unmanaged.Method(pinBatteryQueryInfo.Pointer); 
0

Dans votre définition PInvoke, déclarez simplement le paramètre char * comme octet [] et le marshaller standard traitera le travail.

Mais cela peut être ou ne pas être la meilleure idée. La fonction C++ attend-elle une chaîne ou attend-elle un tampon de données (le code C/C++ utilise souvent char * pour un tampon, en s'appuyant sur le fait qu'un char est un octet)? S'il s'agit d'un tampon alors un octet [] est certainement correct, mais s'il attend une chaîne, il peut être plus clair si vous déclarez le paramètre comme une chaîne (pour être explicite) et utilisez Encoding.ASCII.GetString () pour convertir l'octet [] en une chaîne. De plus, si la fonction C++ attend une chaîne et que vous décidez de déclarer le paramètre comme octet [], assurez-vous que le tableau d'octets se termine par un zéro, puisque c'est ainsi que C/C++ détermine la fin de la chaîne.