comportement de marshaling par défautDefault Marshaling Behavior

Le marshaling d'interopérabilité agit sur les règles qui définissent le comportement des données associées aux paramètres de méthode quand elles sont passées de la mémoire managée à la mémoire non managée.Interop marshaling operates on rules that dictate how data associated with method parameters behaves as it passes between managed and unmanaged memory. Ces règles intégrées contrôlent les activités de marshaling telles que les transformations de types de données, le fait qu’un appelant puisse modifier les données transmises et renvoyer ces modifications à l’appelant, ainsi que les circonstances dans lesquelles le marshaleur fournit des optimisations de performances.These built-in rules control such marshaling activities as data type transformations, whether a callee can change data passed to it and return those changes to the caller, and under which circumstances the marshaler provides performance optimizations.

Cette section aborde les caractéristiques de comportement par défaut du service de marshaling d'interopérabilité.This section identifies the default behavioral characteristics of the interop marshaling service. Elle présente des informations détaillées sur le marshaling des tableaux, des types booléens, des types char, des délégués, des classes, des objets, des chaînes et des structures.It presents detailed information on marshaling arrays, Boolean types, char types, delegates, classes, objects, strings, and structures.

Notes

Le marshaling des types génériques n'est pas pris en charge.Marshaling of generic types is not supported. Pour plus d’informations, consultez Interopérabilité à l’aide de types génériques.For more information see, Interoperating Using Generic Types.

Gestion de la mémoire avec le marshaleur d'interopérabilitéMemory management with the interop marshaler

Le marshaleur d'interopérabilité tente toujours de libérer de la mémoire allouée par du code non managé.The interop marshaler always attempts to free memory allocated by unmanaged code. Ce comportement est conforme aux règles de gestion de mémoire COM, mais pas à celles qui régissent le code C++ natif.This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

Vous pouvez créer une confusion si vous anticipez le comportement du C++ natif (aucune libération de mémoire) lors d‘un appel de code non managé qui libère automatiquement de la mémoire pour les pointeurs.Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. Par exemple, l'appel de la méthode non managée suivante à partir d'une DLL C++ ne libère pas automatiquement de la mémoire.For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

Signature non managéeUnmanaged signature

BSTR MethodOne (BSTR b) {  
     return b;  
}  

Toutefois, si vous définissez la méthode comme un prototype d’appel de code non managé, puis remplacez chaque type BSTR par un type String et appelez MethodOne, le common language runtime tentera de libérer b deux fois.However, if you define the method as a platform invoke prototype, replace each BSTR type with a String type, and call MethodOne, the common language runtime attempts to free b twice. Vous pouvez modifier le comportement de marshaling en utilisant les types IntPtr plutôt que les types String.You can change the marshaling behavior by using IntPtr types rather than String types.

Le runtime utilise toujours la méthode CoTaskMemFree pour libérer de la mémoire.The runtime always uses the CoTaskMemFree method to free memory. Si la mémoire que vous utilisez n’a pas été allouée avec la méthode CoTaskMemAlloc, vous devez utiliser un IntPtr et libérer la mémoire manuellement à l’aide de la méthode appropriée.If the memory you are working with was not allocated with the CoTaskMemAlloc method, you must use an IntPtr and free the memory manually using the appropriate method. De même, vous pouvez éviter la libération automatique de mémoire dans les cas où celle-ci ne doit jamais être libérée, par exemple quand vous utilisez la fonction GetCommandLine depuis Kernel32.dll qui retourne un pointeur à la mémoire du noyau.Similarly, you can avoid automatic memory freeing in situations where memory should never be freed, such as when using the GetCommandLine function from Kernel32.dll, which returns a pointer to kernel memory. Pour plus d’informations sur la libération manuelle de mémoire, consultez Mémoires tampons, exemple.For details on manually freeing memory, see the Buffers Sample.

Marshaling par défaut pour les classesDefault marshaling for classes

Les classes ne peuvent être marshalées que par COM Interop et sont toujours marshalées en tant qu’interfaces.Classes can be marshaled only by COM interop and are always marshaled as interfaces. Dans certains cas, l’interface utilisée pour marshaler la classe est appelée interface de classe.In some cases the interface used to marshal the class is known as the class interface. Pour plus d’informations sur la substitution de l’interface de classe par une interface de votre choix, consultez Présentation de l’interface de classe.For information about overriding the class interface with an interface of your choice, see Introducing the class interface.

Passage de classes à COMPassing Classes to COM

Quand une classe managée est passée à COM, le marshaleur d’interopérabilité encapsule automatiquement la classe avec un proxy COM et passe l’interface de classe produite par le proxy à l’appel de méthode COM.When a managed class is passed to COM, the interop marshaler automatically wraps the class with a COM proxy and passes the class interface produced by the proxy to the COM method call. Le proxy délègue ensuite tous les appels sur l'interface de classe vers l'objet managé.The proxy then delegates all calls on the class interface back to the managed object. Le proxy expose également d'autres interfaces qui ne sont pas explicitement implémentées par la classe.The proxy also exposes other interfaces that are not explicitly implemented by the class. Le proxy implémente automatiquement les interfaces telles que IUnknown et IDispatch pour le compte de la classe.The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.

Passage de classes à du code .NETPassing Classes to .NET Code

Les coclasses ne sont généralement pas utilisées en tant qu'arguments de méthode dans COM.Coclasses are not typically used as method arguments in COM. Au lieu d’une coclasse, c’est une interface par défaut qui est généralement passée.Instead, a default interface is usually passed in place of the coclass.

Quand une interface est passée dans du code managé, le marshaleur d’interopérabilité est responsable de l’encapsulation de l’interface avec le wrapper approprié et du passage du wrapper à la méthode managée.When an interface is passed into managed code, the interop marshaler is responsible for wrapping the interface with the proper wrapper and passing the wrapper to the managed method. Savoir quel wrapper utiliser peut s'avérer difficile.Determining which wrapper to use can be difficult. Chaque instance d'un objet COM possède un seul et unique wrapper, quel que soit le nombre d'interfaces qu'implémente l'objet.Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. Par exemple, un objet COM qui implémente cinq interfaces différentes n'a qu'un seul wrapper.For example, a single COM object that implements five distinct interfaces has only one wrapper. Le même wrapper expose les cinq interfaces.The same wrapper exposes all five interfaces. Si deux instances de l'objet COM sont créées, deux instances du wrapper sont créées.If two instances of the COM object are created, then two instances of the wrapper are created.

Pour que le wrapper conserve le même type durant toute sa durée de vie, le marshaleur d’interopérabilité doit identifier le bon wrapper la première fois qu’une interface exposée par l’objet est passée via le marshaleur.For the wrapper to maintain the same type throughout its lifetime, the interop marshaler must identify the correct wrapper the first time an interface exposed by the object is passed through the marshaler. Le marshaleur identifie l’objet en examinant l’une des interfaces implémentées par l’objet.The marshaler identifies the object by looking at one of the interfaces the object implements.

Par exemple, le marshaleur détermine que le wrapper de classe doit être utilisé pour encapsuler l’interface qui a été passée dans le code managé.For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. Quand l'interface est initialement passée via le marshaleur, celui-ci vérifie si l'interface provient d'un objet connu.When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. Cette vérification se produit dans deux situations :This check occurs in two situations:

  • Une interface est implémentée par un autre objet managé qui a été passé à COM à un autre endroit.An interface is being implemented by another managed object that was passed to COM elsewhere. Le marshaleur peut facilement identifier les interfaces exposées par les objets managés. De plus, il est capable de faire correspondre l'interface avec l'objet managé qui fournit l'implémentation.The marshaler can readily identify interfaces exposed by managed objects and is able to match the interface with the managed object that provides the implementation. L'objet managé est ensuite passé à la méthode sans qu'aucun wrapper ne soit nécessaire.The managed object is then passed to the method and no wrapper is needed.

  • Un objet qui a déjà été encapsulé implémente l'interface.An object that has already been wrapped is implementing the interface. Afin de déterminer si tel est le cas, le marshaleur interroge l’objet au sujet de son interface IUnknown et compare l’interface retournée aux interfaces des autres objets déjà enveloppés.To determine whether this is the case, the marshaler queries the object for its IUnknown interface and compares the returned interface to the interfaces of other objects that are already wrapped. Si l'interface est identique à celle d'un autre wrapper, les objets ont la même identité et le wrapper existant est passé à la méthode.If the interface is the same as that of another wrapper, the objects have the same identity and the existing wrapper is passed to the method.

Si une interface n’est pas d’un objet connu, le marshaleur effectue ce qui suit :If an interface is not from a known object, the marshaler does the following:

  1. Le marshaleur interroge l’objet au sujet de l’interface IProvideClassInfo2.The marshaler queries the object for the IProvideClassInfo2 interface. Si celle-ci est fournie, le marshaleur utilise le CLSID retourné à partir d’IProvideClassInfo2.GetGUID pour identifier la coclasse fournissant l’interface.If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. Grâce au CLSID, le marshaleur peut localiser le wrapper à partir du Registre si l’assembly a déjà été inscrit.With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.

  2. Le marshaleur interroge l’interface au sujet de l’interface IProvideClassInfo.The marshaler queries the interface for the IProvideClassInfo interface. Si celle-ci est fournie, le marshaleur utilise l’ITypeInfo retourné à partir d’IProvideClassInfo.GetClassinfo pour déterminer le CLSID de la classe exposant l’interface.If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. Le marshaleur peut utiliser le CLSID pour localiser les métadonnées du wrapper.The marshaler can use the CLSID to locate the metadata for the wrapper.

  3. Si le marshaleur ne peut toujours pas identifier la classe, il enveloppe l’interface avec une classe wrapper générique appelée System.__ComObject.If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.

Marshaling par défaut pour les déléguésDefault marshaling for delegates

Un délégué managé est marshalé comme une interface COM ou comme un pointeur fonction, en fonction du mécanisme d’appel :A managed delegate is marshaled as a COM interface or as a function pointer, based on the calling mechanism:

  • Pour un appel de code non managé, un délégué est marshalé en tant que pointeur fonction non managé par défaut.For platform invoke, a delegate is marshaled as an unmanaged function pointer by default.

  • Pour COM Interop, un délégué est marshalé comme une interface COM de type _Delegate par défaut.For COM interop, a delegate is marshaled as a COM interface of type _Delegate by default. L’interface _Delegate est définie dans la bibliothèque de types Mscorlib.tlb et contient la méthode Delegate.DynamicInvoke qui permet d’appeler la méthode que le délégué référence.The _Delegate interface is defined in the Mscorlib.tlb type library and contains the Delegate.DynamicInvoke method, which enables you to call the method that the delegate references.

Le tableau suivant montre les options de marshaling pour le type de données délégué managé.The following table shows the marshaling options for the managed delegate data type. L'attribut MarshalAsAttribute fournit plusieurs valeurs d'énumération UnmanagedType pour marshaler les délégués.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal delegates.

Type d'énumérationEnumeration type Description du format non managéDescription of unmanaged format
UnmanagedType.FunctionPtrUnmanagedType.FunctionPtr Pointeur fonction non managé.An unmanaged function pointer.
UnmanagedType.InterfaceUnmanagedType.Interface Interface de type _Delegate, comme défini dans Mscorlib.tlb.An interface of type _Delegate, as defined in Mscorlib.tlb.

Examinez l'exemple de code suivant dans lequel les méthodes de DelegateTestInterface sont exportées vers une bibliothèque de types COM.Consider the following example code in which the methods of DelegateTestInterface are exported to a COM type library. Remarquez que seuls les délégués marqués à l’aide du mot clé ref (ou ByRef) sont passés en tant que paramètres en entrée/sortie.Notice that only delegates marked with the ref (or ByRef) keyword are passed as In/Out parameters.

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 d'une bibliothèque de typesType library representation

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é, comme n'importe quel autre pointeur fonction non managé.A function pointer can be dereferenced, just as any other unmanaged function pointer can be dereferenced.

Dans cet exemple, quand les deux délégués sont marshalés sous la forme UnmanagedType.FunctionPtr, le résultat est un int et un pointeur vers un int.In this example, when the two delegates are marshaled as UnmanagedType.FunctionPtr, the result is an int and a pointer to an int. Comme les types délégués sont marshalés, int représente ici un pointeur vers une valeur void (void*), qui est l’adresse du délégué en mémoire.Because delegate types are being marshaled, int here represents a pointer to a void (void*), which is the address of the delegate in memory. En d’autres termes, ce résultat est spécifique des systèmes Windows 32 bits, car int représente ici la taille du pointeur de fonction.In other words, this result is specific to 32-bit Windows systems, since int here represents the size of the function pointer.

Notes

Une référence au pointeur fonction d’un délégué managé compris dans du code non managé n’empêche pas le common language runtime d’effectuer le garbage collection sur l’objet managé.A reference to the function pointer to a managed delegate held by unmanaged code does not prevent the common language runtime from performing garbage collection on the managed object.

Par exemple, le code suivant est incorrect, car la référence à l'objet cb passé à la méthode SetChangeHandler ne permet pas à cb de rester actif au-delà de la durée de vie de la méthode Test.For example, the following code is incorrect because the reference to the cb object, passed to the SetChangeHandler method, does not keep cb alive beyond the life of the Test method. Une fois l'objet cb collecté, le pointeur fonction passé à SetChangeHandler n'est plus valide.Once the cb object is garbage collected, the function pointer passed to SetChangeHandler is no longer valid.

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 collection inattendus, l'appelant doit s'assurer que l'objet cb reste actif aussi longtemps que le pointeur fonction non managé est utilisé.To compensate for unexpected garbage collection, the caller must ensure that the cb object is kept alive as long as the unmanaged function pointer is in use. Si vous le souhaitez, vous pouvez faire en sorte que le code non managé informe le code managé quand le pointeur fonction n'est plus utile, comme dans l'exemple suivant.Optionally, you can have the unmanaged code notify the managed code when the function pointer is no longer needed, as the following example shows.

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;  
   }  
}  

Marshaling par défaut des types valeurDefault marshaling for value types

La plupart des types valeur, tels que les nombres entiers et à virgule flottante, sont blittables et ne nécessitent pas de marshaling.Most value types, such as integers and floating-point numbers, are blittable and do not require marshaling. D’autres types non blittables ont des représentations différentes selon qu’ils sont en mémoire managée et non managée. De plus, ils nécessitent d’être marshalés.Other non-blittable types have dissimilar representations in managed and unmanaged memory and do require marshaling. D'autres encore nécessitent une mise en forme explicite au-delà des limites d'interopération.Still other types require explicit formatting across the interoperation boundary.

Cette section fournit des informations sur les types valeur mis en forme suivants :This section provides information on the following formatted value types:

En plus de décrire les types mis en forme, cette rubrique répertorie les types valeur système qui ont un comportement de marshaling inhabituel.In addition to describing formatted types, this topic identifies System Value Types that have unusual marshaling behavior.

Un type mis en forme est un type complexe qui contient des informations qui contrôlent explicitement la disposition de ses membres dans la mémoire.A formatted type is a complex type that contains information that explicitly controls the layout of its members in memory. Les informations de disposition des membres sont obtenues à l'aide de l'attribut StructLayoutAttribute.The member layout information is provided using the StructLayoutAttribute attribute. La disposition peut correspondre à l'une des valeurs d'énumération LayoutKind suivantes :The layout can be one of the following LayoutKind enumeration values:

  • LayoutKind.AutomaticLayoutKind.Automatic

    Indique que le common language runtime est libre de réorganiser les membres du type pour une plus grande efficacité.Indicates that the common language runtime is free to reorder the members of the type for efficiency. Toutefois, quand un type valeur est passé à du code non managé, la disposition des membres est prévisible.However, when a value type is passed to unmanaged code, the layout of the members is predictable. Si vous tentez de marshaler une telle structure, une exception sera automatiquement levée.An attempt to marshal such a structure automatically causes an exception.

  • LayoutKind.SequentialLayoutKind.Sequential

    Indique que les membres du type doivent être disposés dans la mémoire non managée dans le même ordre que celui de la définition de type managé.Indicates that the members of the type are to be laid out in unmanaged memory in the same order in which they appear in the managed type definition.

  • LayoutKind.ExplicitLayoutKind.Explicit

    Indique que les membres sont disposés selon le FieldOffsetAttribute fourni avec chaque champ.Indicates that the members are laid out according to the FieldOffsetAttribute supplied with each field.

Types valeur utilisés dans un appel de code non managéValue Types Used in Platform Invoke

Dans l’exemple suivant, les types Point et Rect fournissent des informations sur la disposition des membres à l’aide de StructLayoutAttribute.In the following example the Point and Rect types provide member layout information using the StructLayoutAttribute.

Imports System.Runtime.InteropServices  
<StructLayout(LayoutKind.Sequential)> Public Structure Point  
   Public x As Integer  
   Public y As Integer  
End Structure  
<StructLayout(LayoutKind.Explicit)> Public Structure Rect  
   <FieldOffset(0)> Public left As Integer  
   <FieldOffset(4)> Public top As Integer  
   <FieldOffset(8)> Public right As Integer  
   <FieldOffset(12)> Public bottom As Integer  
End Structure  
using System.Runtime.InteropServices;  
[StructLayout(LayoutKind.Sequential)]  
public struct Point {  
   public int x;  
   public int y;  
}     
  
[StructLayout(LayoutKind.Explicit)]  
public struct Rect {  
   [FieldOffset(0)] public int left;  
   [FieldOffset(4)] public int top;  
   [FieldOffset(8)] public int right;  
   [FieldOffset(12)] public int bottom;  
}  

Quand ils sont marshalés vers du code non managé, ces types mis en forme sont marshalés en tant que structures de style C.When marshaled to unmanaged code, these formatted types are marshaled as C-style structures. Ceci facilite les appels d’API non managées qui possèdent des arguments de structure.This provides an easy way of calling an unmanaged API that has structure arguments. Par exemple, les structures POINT et RECT peuvent être passées à la fonction PtInRect de l’API Microsoft Windows de la façon suivante :For example, the POINT and RECT structures can be passed to the Microsoft Windows API PtInRect function as follows:

BOOL PtInRect(const RECT *lprc, POINT pt);  

Vous pouvez passer des structures à l'aide de la définition d'appel de code non managé suivante :You can pass structures using the following platform invoke definition:

Friend Class NativeMethods
    Friend Declare Auto Function PtInRect Lib "User32.dll" (
        ByRef r As Rect, p As Point) As Boolean
End Class
internal static class NativeMethods
{
   [DllImport("User32.dll")]
   internal static extern bool PtInRect(ref Rect r, Point p);
}

Le type valeur Rect doit être passé par référence, car l'API non managée s'attend à ce qu'un pointeur vers un RECT soit passé à la fonction.The Rect value type must be passed by reference because the unmanaged API is expecting a pointer to a RECT to be passed to the function. Le type valeur Point est passé par valeur, car l'API non managée s'attend à ce que le POINT soit passé à la pile.The Point value type is passed by value because the unmanaged API expects the POINT to be passed on the stack. Cette différence subtile est très importante.This subtle difference is very important. Les références sont passées au code non managé comme des pointeurs.References are passed to unmanaged code as pointers. Les valeurs sont passées au code non managé sur la pile.Values are passed to unmanaged code on the stack.

Notes

Quand un type mis en forme est marshalé en tant que structure, seuls les champs du type sont accessibles.When a formatted type is marshaled as a structure, only the fields within the type are accessible. Si le type possède des méthodes, des propriétés ou des événements, ceux-ci sont inaccessibles depuis le code non managé.If the type has methods, properties, or events, they are inaccessible from unmanaged code.

Les classes peuvent également être marshalées vers du code non managé en tant que structures de style C, du moment que la disposition des membres est fixe.Classes can also be marshaled to unmanaged code as C-style structures, provided they have fixed member layout. Les informations de disposition des membres des classes sont également fournies avec l'attribut StructLayoutAttribute.The member layout information for a class is also provided with the StructLayoutAttribute attribute. La principale différence entre les types valeur à disposition fixe et les classes à disposition fixe est la manière dont ils sont marshalés vers le code non managé.The main difference between value types with fixed layout and classes with fixed layout is the way in which they are marshaled to unmanaged code. Les types valeur sont passés par valeur (dans la pile). Toutes les modifications apportées par l'appelé aux membres du type ne sont donc pas vues par l'appelant.Value types are passed by value (on the stack) and consequently any changes made to the members of the type by the callee are not seen by the caller. Les types référence sont passés par référence (une référence au type est passée sur la pile). Toutes les modifications apportées par l'appelé aux membres d'un type blittable sont donc vues par l'appelant.Reference types are passed by reference (a reference to the type is passed on the stack); consequently, all changes made to blittable-type members of a type by the callee are seen by the caller.

Notes

Si un type référence possède des membres de type non blittable, la conversion est requise deux fois : la première fois quand un argument est passé du côté non managé, la seconde fois lors du retour de l'appel.If a reference type has members of non-blittable types, conversion is required twice: the first time when an argument is passed to the unmanaged side and the second time on return from the call. En raison de cette charge mémoire supplémentaire, les paramètres In/Out doivent être explicitement appliqués à un argument si l'appelant veut voir les modifications apportées par l'appelé.Due to this added overhead, In/Out parameters must be explicitly applied to an argument if the caller wants to see changes made by the callee.

Dans l’exemple suivant, la classe SystemTime a une disposition séquentielle des membres et peut être passée à la fonction GetSystemTime de l’API Windows.In the following example, the SystemTime class has sequential member layout and can be passed to the Windows API GetSystemTime function.

<StructLayout(LayoutKind.Sequential)> Public Class SystemTime  
   Public wYear As System.UInt16  
   Public wMonth As System.UInt16  
   Public wDayOfWeek As System.UInt16  
   Public wDay As System.UInt16  
   Public wHour As System.UInt16  
   Public wMinute As System.UInt16  
   Public wSecond As System.UInt16  
   Public wMilliseconds As System.UInt16  
End Class  
[StructLayout(LayoutKind.Sequential)]  
   public class SystemTime {  
   public ushort wYear;   
   public ushort wMonth;  
   public ushort wDayOfWeek;   
   public ushort wDay;   
   public ushort wHour;   
   public ushort wMinute;   
   public ushort wSecond;   
   public ushort wMilliseconds;   
}  

La fonction GetSystemTime est définie comme suit :The GetSystemTime function is defined as follows:

void GetSystemTime(SYSTEMTIME* SystemTime);  

La définition d’appel de code non managé équivalente à GetSystemTime se présente comme suit :The equivalent platform invoke definition for GetSystemTime is as follows:

Friend Class NativeMethods
    Friend Declare Auto Sub GetSystemTime Lib "Kernel32.dll" (
        ByVal sysTime As SystemTime)
End Class
internal static class NativeMethods
{
   [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
   internal static extern void GetSystemTime(SystemTime st);
}

Notez que l'argument SystemTime n'est pas typé comme un argument de référence, car SystemTime est une classe et non un type valeur.Notice that the SystemTime argument is not typed as a reference argument because SystemTime is a class, not a value type. Contrairement aux types valeur, les classes sont toujours passées par référence.Unlike value types, classes are always passed by reference.

L'exemple de code suivant montre une autre classe Point qui possède une méthode appelée SetXY.The following code example shows a different Point class that has a method called SetXY. Étant donné que le type a une disposition séquentielle, il peut être passé au code non managé et marshalé comme une structure.Because the type has sequential layout, it can be passed to unmanaged code and marshaled as a structure. Toutefois, le membre SetXY ne peut pas être appelé depuis du code non managé, même si l'objet est passé par référence.However, the SetXY member is not callable from unmanaged code, even though the object is passed by reference.

<StructLayout(LayoutKind.Sequential)> Public Class Point  
   Private x, y As Integer  
   Public Sub SetXY(x As Integer, y As Integer)  
      Me.x = x  
      Me.y = y  
   End Sub  
End Class  
[StructLayout(LayoutKind.Sequential)]  
public class Point {  
   int x, y;  
   public void SetXY(int x, int y){   
      this.x = x;  
      this.y = y;  
   }  
}  

Types valeur utilisés dans COM InteropValue Types Used in COM Interop

Les types mis en forme peuvent également être passés aux appels de méthode d'interopérabilité COM.Formatted types can also be passed to COM interop method calls. En effet, quand ils sont exportés vers une bibliothèque de types, les types valeur sont convertis automatiquement en structures.In fact, when exported to a type library, value types are automatically converted to structures. Comme dans l'exemple suivant, le type valeur Point devient une définition de type (typedef) portant le nom Point.As the following example shows, the Point value type becomes a type definition (typedef) with the name Point. Toutes les références au type valeur Point situées ailleurs que dans la bibliothèque de types sont remplacées par le typedef Point.All references to the Point value type elsewhere in the type library are replaced with the Point typedef.

Représentation d’une bibliothèque de typesType library representation

typedef struct tagPoint {  
   int x;  
   int y;  
} Point;  
interface _Graphics {  
   …  
   HRESULT SetPoint ([in] Point p)  
   HRESULT SetPointRef ([in,out] Point *p)  
   HRESULT GetPoint ([out,retval] Point *p)  
}  

Les règles utilisées pour marshaler des valeurs et des références aux appels de code non managé sont également utilisées lors du marshaling via les interfaces COM.The same rules used to marshal values and references to platform invoke calls are used when marshaling through COM interfaces. Par exemple, quand une instance du type valeur Point est passée de .NET Framework à COM, le Point est passé par valeur.For example, when an instance of the Point value type is passed from the .NET Framework to COM, the Point is passed by value. Si le type valeur Point est passé par référence, un pointeur vers un Point est passé sur la pile.If the Point value type is passed by reference, a pointer to a Point is passed on the stack. Le marshaleur d’interopérabilité ne prend pas en charge les niveaux élevés d’indirection (Point **) dans les deux directions.The interop marshaler does not support higher levels of indirection (Point **) in either direction.

Notes

Les structures dont la valeur d’énumération LayoutKind est définie sur Explicit ne peuvent pas être utilisées dans COM Interop, car la bibliothèque de types exportée ne peut pas exprimer une disposition explicite.Structures having the LayoutKind enumeration value set to Explicit cannot be used in COM interop because the exported type library cannot express an explicit layout.

Types de valeur systèmeSystem Value Types

L'espace de noms System possède plusieurs types valeur qui représentent la forme boxed de types primitifs de runtime.The System namespace has several value types that represent the boxed form of the runtime primitive types. Par exemple, la structure de type valeur System.Int32 représente la forme boxed d’ELEMENT_TYPE_I4.For example, the value type System.Int32 structure represents the boxed form of ELEMENT_TYPE_I4. Au lieu de marshaler ces types en tant que structures, comme le sont les autres types mis en forme, vous les marshalez de la même façon que les types primitifs boxed.Instead of marshaling these types as structures, as other formatted types are, you marshal them in the same way as the primitive types they box. System.Int32 est donc marshalé en tant qu’ELEMENT_TYPE_I4 et non en tant que structure contenant un seul membre de type long.System.Int32 is therefore marshaled as ELEMENT_TYPE_I4 instead of as a structure containing a single member of type long. Le tableau suivant répertorie les types valeur de l’espace de noms System qui sont des représentations boxed de types primitifs.The following table contains a list of the value types in the System namespace that are boxed representations of primitive types.

Type de valeur systèmeSystem value type Type d'élémentElement type
System.Boolean ELEMENT_TYPE_BOOLEANELEMENT_TYPE_BOOLEAN
System.SByte ELEMENT_TYPE_I1ELEMENT_TYPE_I1
System.Byte ELEMENT_TYPE_UI1ELEMENT_TYPE_UI1
System.Char ELEMENT_TYPE_CHARELEMENT_TYPE_CHAR
System.Int16 ELEMENT_TYPE_I2ELEMENT_TYPE_I2
System.UInt16 ELEMENT_TYPE_U2ELEMENT_TYPE_U2
System.Int32 ELEMENT_TYPE_I4ELEMENT_TYPE_I4
System.UInt32 ELEMENT_TYPE_U4ELEMENT_TYPE_U4
System.Int64 ELEMENT_TYPE_I8ELEMENT_TYPE_I8
System.UInt64 ELEMENT_TYPE_U8ELEMENT_TYPE_U8
System.Single ELEMENT_TYPE_R4ELEMENT_TYPE_R4
System.Double ELEMENT_TYPE_R8ELEMENT_TYPE_R8
System.String ELEMENT_TYPE_STRINGELEMENT_TYPE_STRING
System.IntPtr ELEMENT_TYPE_IELEMENT_TYPE_I
System.UIntPtr ELEMENT_TYPE_UELEMENT_TYPE_U

Certains autres types valeur de l’espace de noms System sont gérés différemment.Some other value types in the System namespace are handled differently. Étant donné que le code non managé possède déjà des formats bien établis pour ces types, le marshaleur possède des règles spéciales pour les marshaler.Because the unmanaged code already has well-established formats for these types, the marshaler has special rules for marshaling them. Le tableau suivant répertorie les types valeur spéciaux de l’espace de noms System, ainsi que le type non managé vers lequel ils sont marshalés.The following table lists the special value types in the System namespace, as well as the unmanaged type they are marshaled to.

Type de valeur systèmeSystem value type Type IDLIDL type
System.DateTime DATEDATE
System.Decimal DECIMALDECIMAL
System.Guid GUIDGUID
System.Drawing.Color OLE_COLOROLE_COLOR

Le code suivant montre la définition des types non managés DATE, GUID, DECIMAL et OLE_COLOR dans la bibliothèque de types Stdole2.The following code shows the definition of the unmanaged types DATE, GUID, DECIMAL, and OLE_COLOR in the Stdole2 type library.

Représentation d'une bibliothèque de typesType library representation

typedef double DATE;  
typedef DWORD OLE_COLOR;  
  
typedef struct tagDEC {  
    USHORT    wReserved;  
    BYTE      scale;  
    BYTE      sign;  
    ULONG     Hi32;  
    ULONGLONG Lo64;  
} DECIMAL;  
  
typedef struct tagGUID {  
    DWORD Data1;  
    WORD  Data2;  
    WORD  Data3;  
    BYTE  Data4[ 8 ];  
} GUID;  

Le code suivant montre les définitions correspondantes dans l'interface IValueTypes.The following code shows the corresponding definitions in the managed IValueTypes interface.

Public Interface IValueTypes  
   Sub M1(d As System.DateTime)  
   Sub M2(d As System.Guid)  
   Sub M3(d As System.Decimal)  
   Sub M4(d As System.Drawing.Color)  
End Interface  
public interface IValueTypes {  
   void M1(System.DateTime d);  
   void M2(System.Guid d);  
   void M3(System.Decimal d);  
   void M4(System.Drawing.Color d);  
}  

Représentation d'une bibliothèque de typesType library representation

[…]  
interface IValueTypes : IDispatch {  
   HRESULT M1([in] DATE d);  
   HRESULT M2([in] GUID d);  
   HRESULT M3([in] DECIMAL d);  
   HRESULT M4([in] OLE_COLOR d);  
};  

Voir aussiSee also