MethodRental.SwapMethodBody(Type, Int32, IntPtr, Int32, Int32) Método

Definición

Intercambia el cuerpo de un método.

public:
 static void SwapMethodBody(Type ^ cls, int methodtoken, IntPtr rgIL, int methodSize, int flags);
public static void SwapMethodBody (Type cls, int methodtoken, IntPtr rgIL, int methodSize, int flags);
static member SwapMethodBody : Type * int * nativeint * int * int -> unit
Public Shared Sub SwapMethodBody (cls As Type, methodtoken As Integer, rgIL As IntPtr, methodSize As Integer, flags As Integer)

Parámetros

cls
Type

Clase que contiene el método.

methodtoken
Int32

Símbolo (token) para el método.

rgIL
IntPtr

nativeint

Puntero al método. Debe incluir el encabezado del método.

methodSize
Int32

Tamaño del nuevo cuerpo del método en bytes.

flags
Int32

Marcadores que controlan el intercambio. Vea las definiciones de las constantes.

Excepciones

cls es null.

El tipo cls no está completo.

methodSize es menor que uno o mayor que 4128767 (3effff hexadecimal).

Ejemplos

En el ejemplo siguiente se muestra cómo intercambiar un cuerpo de método para un nuevo cuerpo. También se muestra cómo obtener un token de método para un método existente y cómo construir un blob de bytes que representa el código de Lenguaje intermedio de Microsoft (MSIL) que se va a pasar a SwapMethodBody.

using namespace System;
using namespace System::Reflection;
using namespace System::Reflection::Emit;
using namespace System::Runtime::InteropServices;

// First make a method that returns 0.
// Then swap the method body with a body that returns 1.
int main()
{
   // Construct a dynamic assembly
   Guid g = Guid::NewGuid();
   AssemblyName^ asmname = gcnew AssemblyName;
   asmname->Name = String::Concat( "tempfile", g );
   AssemblyBuilder^ asmbuild = System::Threading::Thread::GetDomain()->DefineDynamicAssembly( asmname, AssemblyBuilderAccess::Run );

   // Add a dynamic module that contains one type that has one method that
   // has no arguments.
   ModuleBuilder^ modbuild = asmbuild->DefineDynamicModule( "test" );
   TypeBuilder^ tb = modbuild->DefineType( "name of the Type" );
   array<Type^>^temp2;
   MethodBuilder^ somemethod = tb->DefineMethod( "My method Name", static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::Static), int::typeid, temp2 );

   // Define the body of the method to return 0.
   ILGenerator^ ilg = somemethod->GetILGenerator();
   ilg->Emit( OpCodes::Ldc_I4_0 );
   ilg->Emit( OpCodes::Ret );

   // Complete the type and verify that it returns 0.
   Type^ tbBaked = tb->CreateType();
   array<Object^>^temp0;
   int res1 = safe_cast<Int32>(tbBaked->GetMethod( "My method Name" )->Invoke( nullptr, temp0 ));
   if ( res1 != 0 )
   {
      Console::WriteLine( "Err_001a, should have returned 0" );
   }
   else
   {
      Console::WriteLine( "Original method returned 0" );
   }

   // Define a new method body that will return a 1 instead.

   // code size
   // ldc_i4_1
   // ret
   array<Byte>^methodBytes = {0x03,0x30,0x0A,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x2a};

   // Get the token for the method whose body you are replacing.
   MethodToken somemethodToken = somemethod->GetToken();

   // Get the pointer to the method body.
   GCHandle hmem = GCHandle::Alloc( (Object^)methodBytes, GCHandleType::Pinned );
   IntPtr addr = hmem.AddrOfPinnedObject();
   int cbSize = methodBytes->Length;

   // Swap the old method body with the new body.
   MethodRental::SwapMethodBody( tbBaked, somemethodToken.Token, addr, cbSize, MethodRental::JitImmediate );

   // Verify that the modified method returns 1.
   array<Object^>^temp1;
   int res2 = safe_cast<Int32>(tbBaked->GetMethod( "My method Name" )->Invoke( nullptr, temp1 ));
   if ( res2 != 1 )
   {
      Console::WriteLine( "Err_001b, should have returned 1" );
   }
   else
   {
      Console::WriteLine( "Swapped method body returned 1" );
   }
}
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

class SwapMethodBodySample
{
    // First make a method that returns 0.
    // Then swap the method body with a body that returns 1.
    public static void Main(string [] args)
    {
    // Construct a dynamic assembly
    Guid g = Guid.NewGuid();
    AssemblyName asmname = new AssemblyName();
    asmname.Name = "tempfile" + g;
    AssemblyBuilder asmbuild = System.Threading.Thread.GetDomain().
        DefineDynamicAssembly(asmname, AssemblyBuilderAccess.Run);

    // Add a dynamic module that contains one type that has one method that
    // has no arguments.
    ModuleBuilder modbuild = asmbuild.DefineDynamicModule( "test");
        TypeBuilder tb = modbuild.DefineType( "name of the Type" );
        MethodBuilder somemethod = tb.DefineMethod
            ("My method Name",
             MethodAttributes.Public | MethodAttributes.Static,
             typeof(int),
             new Type[]{} );
    // Define the body of the method to return 0.
        ILGenerator ilg = somemethod.GetILGenerator();
    ilg.Emit(OpCodes.Ldc_I4_0);
    ilg.Emit(OpCodes.Ret);

    // Complete the type and verify that it returns 0.
    Type tbBaked = tb.CreateType();
    int res1 = (int)tbBaked.GetMethod("My method Name").Invoke( null, new Object[]{} );
    if ( res1 != 0 ) {
        Console.WriteLine( "Err_001a, should have returned 0" );
    } else {
        Console.WriteLine("Original method returned 0");
    }

    // Define a new method body that will return a 1 instead.
    Byte[] methodBytes = {
        0x03,
        0x30,
        0x0A,
        0x00,
        0x02,                // code size
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x17,                // ldc_i4_1
        0x2a                // ret
    };

    // Get the token for the method whose body you are replacing.
    MethodToken somemethodToken = somemethod.GetToken();

    // Get the pointer to the method body.
        GCHandle hmem = GCHandle.Alloc((Object) methodBytes, GCHandleType.Pinned);
        IntPtr addr = hmem.AddrOfPinnedObject();
    int cbSize = methodBytes.Length;

    // Swap the old method body with the new body.
    MethodRental.SwapMethodBody(
                    tbBaked,
                    somemethodToken.Token,
                    addr,
                    cbSize,
                    MethodRental.JitImmediate);

    // Verify that the modified method returns 1.
    int res2 = (int)tbBaked.GetMethod("My method Name").Invoke( null, new Object[]{} );
    if ( res2 != 1 ) {
        Console.WriteLine( "Err_001b, should have returned 1" );
    } else {
        Console.WriteLine("Swapped method body returned 1");
    }
    }
}
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Runtime.InteropServices

Class SwapMethodBodySample
    
    ' First make a method that returns 0.
    ' Then swap the method body with a body that returns 1.
    Public Shared Sub Main()
        ' Construct a dynamic assembly
        Dim g As Guid = Guid.NewGuid()
        Dim asmname As New AssemblyName()
        asmname.Name = "tempfile" + g.ToString()
        Dim asmbuild As AssemblyBuilder = _
           System.Threading.Thread.GetDomain().DefineDynamicAssembly _
           (asmname, AssemblyBuilderAccess.Run)
        
        ' Add a dynamic module that contains one type that has one method that
        ' has no arguments.
        Dim modbuild As ModuleBuilder = asmbuild.DefineDynamicModule("test")
        Dim tb As TypeBuilder = modbuild.DefineType("name of the Type")
        Dim somemethod As MethodBuilder = _
           tb.DefineMethod("My method Name", _
           MethodAttributes.Public Or(MethodAttributes.Static), _
           GetType(Integer), New Type() {})
        ' Define the body of the method to return 0.
        Dim ilg As ILGenerator = somemethod.GetILGenerator()
        ilg.Emit(OpCodes.Ldc_I4_0)
        ilg.Emit(OpCodes.Ret)
        
        ' Complete the type and verify that it returns 0.
        Dim tbBaked As Type = tb.CreateType()
        Dim res1 As Integer = _
           CInt(tbBaked.GetMethod("My method Name").Invoke _
           (Nothing, New Object() {}))
        If res1 <> 0 Then
            Console.WriteLine("Err_001a, should have returned 0")
        Else
            Console.WriteLine("Original method returned 0")
        End If
        
        ' Define a new method body that will return a 1 instead.
        Dim methodBytes As Byte() = _
        {&H3, &H30, &HA, &H0, &H2, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H17, &H2A}
        '&H2     code size
        '&H17    ldc_i4_1
        '&H2A    ret
        
        ' Get the token for the method whose body you are replacing.
        Dim somemethodToken As MethodToken = somemethod.GetToken()
        
        ' Get the pointer to the method body.
        Dim hmem As GCHandle = _
           GCHandle.Alloc(CType(methodBytes, Object), GCHandleType.Pinned)
        Dim addr As IntPtr = hmem.AddrOfPinnedObject()
        Dim cbSize As Integer = methodBytes.Length
        
        ' Swap the old method body with the new body.
        MethodRental.SwapMethodBody(tbBaked, somemethodToken.Token, addr, _
           cbSize, MethodRental.JitImmediate)
        
        ' Verify that the modified method returns 1.
        Dim res2 As Integer = _
           CInt(tbBaked.GetMethod("My method Name").Invoke _
           (Nothing, New Object() {}))
        If res2 <> 1 Then
            Console.WriteLine("Err_001b, should have returned 1")
        Else
            Console.WriteLine("Swapped method body returned 1")
        End If
    End Sub
End Class

Comentarios

No puede usar este método para intercambiar el cuerpo de un método global.

El cliente que creó el módulo dinámico que contiene el tipo cuyo cuerpo del método se está intercambiando solo puede llamar al método.

Se aplica a