Partager via


Traductions de signatures de méthodes implicites dans l’interopérabilité .NET

Pour rester indépendant du langage de programmation, le système COM Windows et de nombreuses API Windows retournent un type entier de 4 octets appelé un HRESULT pour indiquer si une API a réussi ou échoué, ainsi que des informations sur l’échec. Les autres valeurs qui doivent être transmises à l’appelant sont « retournées » via des paramètres de pointeur qui agissent comme des paramètres « sortants » et sont généralement le dernier paramètre de la signature. Les langages tels que C# et Visual Basic traduisent traditionnellement un code d’échec en exception pour correspondre à la façon dont les échecs sont généralement propagés dans la langue et s’attendent à ce que les signatures de méthode d’interopérabilité n’incluent pas le HRESULT. Pour traduire la signature de méthode en signature native, le runtime déplace la valeur renvoyée de la méthode vers un paramètre « sortant » supplémentaire avec un niveau d’indirection supplémentaire (en d’autres termes, il en fait un pointeur sur le type de retour de la signature managée) et suppose une valeur de retour HRESULT. Si la méthode managée retourne void, aucun paramètre supplémentaire n’est ajouté et la valeur renvoyée devient un HRESULT. Par exemple, consultez les deux méthodes COM C# suivantes qui se traduisent par la même signature native :

int Add(int a, int b);

void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);

PreserveSig dans COM

Toutes les méthodes COM en C# sont censées utiliser la signature traduite par défaut. Pour utiliser et exporter des méthodes sans traduction de signature et gestion des valeurs HRESULT, ajoutez le PreserveSigAttribute à une méthode d’interface COM. Lorsque l’attribut est appliqué à une méthode, aucune traduction n’est effectuée vers la signature, et les exceptions ne sont pas levées pour les valeurs HRESULT défaillantes. Cela s’applique à la fois à COM intégré et à COM généré par la source. Par exemple, consultez la signature de méthode C# suivante avec un attribut PreserveSig et sa signature native correspondante.

[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);

Cela peut être utile si la méthode peut retourner différentes valeurs HRESULT qui ne sont pas des échecs, mais doit être gérée différemment. Par exemple, certaines méthodes peuvent renvoyer la valeur S_FALSE lorsqu’une méthode n’échoue pas, mais retourne uniquement des résultats partiels, et S_OK lorsqu’elle retourne tous les résultats.

PreserveSig avec P/Invokes

L’attribut DllImportAttribute a également le champ bool PreserveSig qui fonctionne de la même manière que le champ PreserveSigAttribute, mais est défini par défaut sur true. Pour indiquer que le runtime doit traduire la signature managée et gérer le HRESULT qui est retourné, définissez le champ PreserveSig sur false dans le DllImportAttribute. Par exemple, consultez les signatures suivantes de deux P/Invokes vers la même méthode native, une avec PreserveSig défini sur false, et une laissée avec la valeur true par défaut.

[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);

Remarque

Les appels P/Invokes générés par la source, qui utilisent le LibraryImportAttribute, n’ont aucun champ PreserveSig. Le code généré suppose toujours que la signature native et la signature gérée sont identiques. Pour plus d’informations, consultez P/Invokes générés par la source.

Gérer manuellement les valeurs HRESULT

Lors de l’appel d’une méthode PreserveSig qui retourne un HRESULT, vous pouvez utiliser la méthode ThrowExceptionForHR pour lever l’exception correspondante si le HRESULT indique un échec. De même, lors de l’implémentation d’une méthode PreserveSig, vous pouvez utiliser la méthode GetHRForException pour retourner le HRESULT qui indique une valeur correspondante pour l’exception.

Marshaler les HRESULT en tant que structs

Lorsque vous utilisez une méthode PreserveSig, on s’attend à ce que int soit le type managé pour HRESULT. Toutefois, l’utilisation d’un struct personnalisé de 4 octets comme type de retour vous permet de définir des méthodes et des propriétés d’assistance qui peuvent simplifier l’utilisation du HRESULT. Dans le marshaling intégré, cela fonctionne automatiquement. Pour utiliser un struct à la place de int en tant que représentation managée de HRESULT dans le marshaling généré par la source, ajoutez l’attribut MarshalAsAttribute avec Error comme argument. La présence de cet attribut réinterprète les bits du HRESULT en tant que struct.

Voir aussi