Modifications de marshaling
Les sections suivantes fournissent un ensemble sélectionné de modifications que vous pouvez apporter à un assembly d'interopérabilité pour résoudre certains problèmes spécifiques liés aux résultats du processus d'importation :
Tableaux conformes au style C
Tableaux de style C entrant/sortant
Tableaux de style C multidimensionnels
SAFEARRAY non limité par zéro
Préservation de la signature
Passer null au lieu d'une référence à un type valeur
Ces sections ne couvrent pas tous les cas d'édition d'un assembly d'interopérabilité. Par exemple, vous pouvez également éditer un assembly d'interopérabilité pour améliorer la simplicité de son utilisation. La seule manière de déterminer les types de personnalisation nécessaires est d'écrire du code à l'aide de l'assembly d'interopérabilité. Pour obtenir des instructions sur la modification des assemblys d'interopérabilité, consultez Comment : modifier des assemblys d'interopérabilité.
Le marshaling est affecté lorsque le client et le serveur résident dans des apartments incompatibles. Dans les exemples suivants, la plupart des paramètres marshalés ne sont pas compatibles avec Automation et nécessitent l'une des actions suivantes :
Confirmez que le client et le serveur résident tous deux dans des apartments compatibles (et qu'il n'y a pas par conséquent de marshaling COM).
Inscrivez le proxy et le stub générés à partir du langage de définition d'interface (IDL). Dans de tels cas, inscrire la bibliothèque de types ne résout pas le problème car l'essentiel des informations nécessaires au marshaling n'est pas propagé de l'IDL vers la bibliothèque de types.
Tableaux conformes au style C
La déclaration IDL suivante illustre un tableau de style C.
HRESULT ConformantArray([in] int cElems, [in, size_is(cElems)] int
aConf[]);
Comme ce type n'est pas compatible avec Automation, les informations sur la taille du tableau, telles que le lien entre le premier et le deuxième paramètre, ne peuvent pas être exprimées dans la bibliothèque de types. L'importateur de bibliothèques de types (Type Library Importer (Tlbimp.exe)) importe le deuxième paramètre comme référence à l'entier et non pas comme tableau managé. Vous pouvez ajuster le paramètre en éditant le MSIL.
Dans MSIL, recherchez
method public hidebysig newslot virtual
instance void ConformantArray([in] int32 cElems,
[in] int32& aConf) runtime managed internalcall
Remplacer par
method public hidebysig newslot virtual
instance void ConformantArray([in] int32 cElems,
[in] int32[] marshal([]) aConf) runtime managed internalcall
Pour appeler à partir d'un code managé
int[] param1 = { 11, 22, 33 };
tstArrays.ConformantArray( 3, param1 );
Tableaux de style C entrant/sortant
La déclaration IDL suivante illustre un tableau de style C entrant/sortant.
HRESULT InOutArray([in, out] int* pcElems, [in, out, size_is(,*pcElems)]
int** ppInOut);
Dans ce cas, le tableau peut être redimensionné et la nouvelle taille peut être passée de nouveau. Comme ce type n'est pas compatible avec Automation, les informations sur la taille du tableau, telles que le lien entre le premier et le deuxième paramètre, ne peuvent pas être exprimées dans la bibliothèque de types. Tlbimp.exe importe le deuxième paramètre comme type IntPtr. Bien qu'il vous soit possible d'appeler cette méthode à partir du code managé, afin de redimensionner le tableau, vous devez éditer le MSIL et utiliser les méthodes de la classe Marshal pour traiter manuellement l'allocation et la désallocation de la mémoire.
Dans MSIL, recherchez
.method public hidebysig newslot virtual
instance void InOutArray([in][out] int32& pcElems,
[in][out] native int ppInOut) runtime managed internalcall
Remplacer par
.method public hidebysig newslot virtual
instance void InOutArray([in][out] int32& pcElems,
[in][out] native int& ppInOut) runtime managed internalcall
Pour appeler à partir d'un code managé
int[] inArray = { 11, 22, 33 };
int arraySize = inArray.Length;
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( typeof( int )) * inArray.Length );
Marshal.Copy( inArray, 0, buffer, inArray.Length );
tstArrays.InOutArray( ref arraySize, ref buffer );
if( arraySize > 0 )
{
int[] arrayRes = new int[ arraySize ];
Marshal.Copy( buffer, arrayRes, 0, arraySize );
Marshal.FreeCoTaskMem( buffer );
}
Tableaux de style C multidimensionnels
La déclaration IDL suivante illustre un tableau de style C à deux dimensions.
HRESULT TwoDimArray([in] int cDim, [in, size_is(cDim)] int aMatrix[][3]);
Comme ce type n'est pas compatible avec Automation, les informations sur la taille et le nombre de dimensions du tableau, telles que le lien entre le premier et le deuxième paramètre, ne peuvent pas être exprimées dans la bibliothèque de types. Tlbimp.exe importe le deuxième paramètre comme type IntPtr et non pas comme tableau multidimensionnel managé. Vous pouvez ajuster le paramètre en éditant le MSIL.
Dans MSIL, recherchez
.method public hidebysig newslot virtual
instance void TwoDimArray([in] int32 cDim,
[in] native int aMatrix) runtime managed internalcall
Remplacer par
.method public hidebysig newslot virtual
instance void TwoDimArray([in] int32 cDim,
[in] int32[,] marshal([]) aMatrix) runtime managed internalcall
Pour appeler à partir d'un code managé
int[,] param = {{ 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 }};
tstArrays.TwoDimArray( 3, param );
SAFEARRAY non limité par zéro
La déclaration IDL suivante illustre un paramètre SAFEARRAY.
HRESULT InSArray([in] SAFEARRAY(int) *ppsa);
Imaginons que SAFEARRAY ne soit pas limité par zéro. Dans du code managé, ces tableaux sont représentés par le type System.Array. Cependant, par défaut, l'importateur convertit tous les paramètres SAFEARRAY sous forme de références à des tableaux managés. Pour modifier le comportement par défaut, deux options s'offrent à vous :
Importer tous les tableaux dans une bibliothèque de types comme types System.Array à l'aide de Tlbimp.exe et du commutateur /sysarray.
Importer quelques paramètres comme types System.Array en éditant manuellement le MSIL comme le montre l'exemple suivant :
Dans MSIL, recherchez
.method public hidebysig newslot virtual instance void InSArray([in] int32[]& marshal( safearray int) ppsa) runtime managed internalcall
Remplacer par
.method public hidebysig newslot virtual instance void InSArray(class [mscorlib]System.Array& marshal( safearray) ppsa) runtime managed internalcall
Pour appeler à partir d'un code managé
int[] lengthsArray = new int[1] { 3 }; int[] boundsArray = new int[1] { -1 }; Array param2 = Array.CreateInstance( typeof(int), lengthsArray, boundsArray ); for( int i = param2.GetLowerBound( 0 ); i <= param2.GetUpperBound( 0 ); i++ ) param2.SetValue( i * 10, i ); sum = tstArrays.InSArray( ref param2 );
Préservation de la signature
La déclaration IDL suivante illustre une signature de méthode COM.
HRESULT TestPreserveSig2([in] int inParam, [out,retval] int* outParam);
Tlbimp.exe change les signatures des méthodes COM. Les paramètres marqués avec [out, retval] dans IDL deviennent des valeurs de retour des méthodes managées. Toutes les valeurs HRESULT qui indiquent un échec sont transformées en exceptions managées. Il est parfois nécessaire de préserver la signature de méthode COM d'origine. Par exemple, lorsque la méthode retourne des valeurs autres que des HRESULT de succès. La représentation managée suivante illustre un exemple de signature que vous pouvez modifier.
Représentation managée dans MSIL
.method public hidebysig newslot virtual
instance int32 TestPreserveSig2([in] int32 inParam) runtime managed internalcall
{
Remplacer par
.method public hidebysig newslot virtual
instance int32 TestPreserveSig2([in] int32 inParam, [out] int32& outParam) runtime managed internalcall preservesig
Pour afficher le type de valeur HRESULT retournée
int hr = tst.TestPreserveSig2( -3, out retValue );
Console.WriteLine( "Return value is {0}", retValue );
if( hr == 0 )
Console.WriteLine( "HRESULT = S_OK" );
else if ( hr == 1 )
Console.WriteLine( "HRESULT = S_FALSE" );
else
Console.WriteLine( "HRESULT = {0}", hr );
Passer null au lieu d'une référence à un type valeur
La déclaration IDL suivante illustre un pointeur IDL vers une structure.
HRESULT TestPassingNull([in, unique] Point* refParam);
Tlbimp.exe importe le paramètre comme référence au type valeur Point. En C# et Visual Basic 2005, une référence null (Nothing en Visual Basic) ne peut pas être passée en tant que paramètre lorsqu'une référence à un type valeur est attendue. Si la fonction COM nécessite un paramètre null (Nothing), vous pouvez modifier la signature en éditant le MSIL.
Dans MSIL, recherchez
.method public hidebysig newslot virtual
instance void TestPassingNull(
[in] valuetype MiscSrv.tagPoint& refParam)
runtime managed internalcall
Remplacer par
.method public hidebysig newslot virtual
instance void TestPassingNull([in] native int) runtime managed internalcall
La signature modifiée vous permet de passer une valeur null. Cependant, lorsque vous avez besoin de passer de vraies valeurs, vous devez utiliser les méthodes de la classe Marshal, comme l'illustre l'exemple suivant.
tagPoint p = new tagPoint();
p.x = 3;
p.y = 9;
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( p ));
Marshal.StructureToPtr( p, buffer, false );
tst.TestPassingNull( buffer );
Marshal.FreeCoTaskMem( buffer );
tst.TestPassingNull( IntPtr.Zero );
Voir aussi
Tâches
Comment : modifier des assemblys d'interopérabilité
Comment : créer manuellement des wrappers
Référence
Tlbimp.exe (Type Library Importer)
Concepts
personnaliser des wrappers pouvant être appelés par le runtime