Marshaling par défaut pour les délégués

Mise à jour : novembre 2007

Un délégué managé est marshalé en tant qu'interface COM ou comme pointeur fonction, en fonction du mécanisme d'appel :

  • Pour l'appel de code non managé, un délégué est marshalé en tant que pointeur fonction non managé par défaut.

  • Pour COM interop, un délégué est marshalé en tant qu'interface COM de type __Delegate par défaut. L'interface _Delegate est définie dans la bibliothèque de types Mscorlib.tlb et contient la méthode Delegate.DynamicInvoke qui vous permet d'appeler la méthode que le délégué référence.

Le tableau suivant affiche les options de marshaling pour les types de données délégués managés. L'attribut MarshalAsAttribute fournit plusieurs valeurs d'énumération UnmanagedType pour marshaler des délégués.

Type énumération

Description de format non managé

UnmanagedType.FunctionPtr

Pointeur fonction non managé.

UnmanagedType.Interface

Interface de type __Delegate, telle qu'elle est définie dans Mscorlib.tlb.

Prenez l'exemple de code suivant dans lequel les méthodes de DelegateTestInterface sont exportées vers une bibliothèque de types COM. Remarquez que seuls les délégués marqués du mot clé ref (ou ByRef) sont passés en tant que paramètres en entrée/sortie.

using System;
using System.Runtime.InteropServices;

public interface DelegateTest {
void m1(Delegate d);
void m2([MarshalAs(UnmanagedType.Interface)] Delegate d);   
void m3([MarshalAs(UnmanagedType.Interface)] ref Delegate d);  
void m4([MarshalAs(UnmanagedType.FunctionPtr)] Delegate d); 
void m5([MarshalAs(UnmanagedType.FunctionPtr)] ref Delegate d);   
}

Représentation de la bibliothèque de types

importlib("mscorlib.tlb");
interface DelegateTest : IDispatch {
[id(…)] HRESULT m1([in] _Delegate* d);
[id(…)] HRESULT m2([in] _Delegate* d);
[id(…)] HRESULT m3([in, out] _Delegate** d);
[id()] HRESULT m4([in] int d);
[id()] HRESULT m5([in, out] int *d);
   };

Un pointeur fonction peut être déréférencé de la même manière que tout autre pointeur fonction non managé.

Remarque :

Une référence au pointeur fonction vers un délégué managé détenu par le code non managé n'empêche pas le Common Language Runtime d'effectuer une opération garbage collection sur l'objet managé.

Par exemple, le code suivant n'est pas correct car la référence à l'objet cb, passée à la méthode SetChangeHandler, ne garde pas cb actif au-delà de la durée de vie de la méthode Test. Une fois que l'objet cb est récupéré par le garbage collector, le pointeur fonction passé à SetChangeHandler n'est plus valide.

public class ExternalAPI {
   [DllImport("External.dll")]
   public static extern void SetChangeHandler(
      [MarshalAs(UnmanagedType.FunctionPtr)]ChangeDelegate d);
}
public delegate bool ChangeDelegate([MarshalAs(UnmanagedType.LPWStr) string S);
public class CallBackClass {
   public bool OnChange(string S){ return true;}
}
internal class DelegateTest {
   public static void Test() {
      CallBackClass cb = new CallBackClass();
      // Caution: The following reference on the cb object does not keep the 
      // object from being garbage collected after the Main method 
      // executes.
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));   
   }
}

Pour compenser les garbage collections inattendus, l'appelant doit veiller à ce que l'objet cb reste actif tant que le pointeur fonction non managé est en cours d'utilisation. Facultativement, vous pouvez faire en sorte que le code non managé notifie le code managé lorsque le pointeur fonction n'est plus nécessaire, comme l'illustre l'exemple suivant.

internal class DelegateTest {
   CallBackClass cb;
   // Called before ever using the callback function.
   public static void SetChangeHandler() {
      cb = new CallBackClass();
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));
   }
   // Called after using the callback function for the last time.
   public static void RemoveChangeHandler() {
      // The cb object can be collected now. The unmanaged code is 
      // finished with the callback function.
      cb = null;
   }
}

Voir aussi

Concepts

Types blittables et non blittables

Attributs directionnels

Copie et épinglage

Autres ressources

Comportement de marshaling par défaut