In my VB.NET application, the event AppDomain.CurrentDomain.AssemblyResolve
has a handler subscribed to it. The ResolveEventHandler
which is subscribed to this event was added upstream from my code (for all I know, System.AppDomain
has its own Private Method
subscribed to the Event)... is it possible to Remove all handlers from this event, so that I can add my own handler and ensure it's the only one?
Essentially I'm trying to do this:
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ClassX.MethodX
But I don't know what ClassX
or MethodX
are in this example because I haven't added a handler to this event yet, and this handler was added by upstream code. I'm using the method described here to check if any handler is subscribed event:
https://stackoverflow.com/a/2953318/734914
Edit: I was able to figure out which method is subscribed to the event, using the Immediate Window while debugging.
? DirectCast(gettype(System.AppDomain).GetField("AssemblyResolve", BindingFlags.Instance or BindingFlags.NonPublic).GetValue(AppDomain.CurrentDomain) , ResolveEventHandler)
{System.ResolveEventHandler}
_methodBase: Nothing
_methodPtr: 157334028
_methodPtrAux: 1827519884
_target: {System.ResolveEventHandler}
**Method: {System.Reflection.Assembly ResolveAssembly**(System.Object, System.ResolveEventArgs)}
Target: Nothing
Now I'm trying to Remove it, like this, because it's not a Public method:
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly")
But that gives a compiler error saying: "AddressOf parameter must be the name of a method". So I'm not sure how to specify a non-Public method here
From the original comment:
Here's a topic about removing delegates from events you don't have the delegate signature to .. pretty handy, but at the end the poster stated
"It looks like AppDomain.CurrentDomain.AssemblyResolve doesn't support removal of events at all so the code I posted won't work."
Even .NET complains that the event System.AppDomain.AssemblyResolve
can only appear on the left hand side of +=
or -=
(+=/-=
operators are the C# AddHandler/RemoveHandler
) .. so it's looking like a 'no' :/
Additionally, after your edits, the reason you can't do the following:
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly")
Is because the AddressOf
keyword is an operator keyword, similar to a +
or -
being an operator, the AddressOf
operates on the procedure given and it must be a procedure name it can deduce at compile time. And the GetMethod
function returns a MethodInfo
type and not a known function address.
All is not lost however!
The AddHandler
and RemoveHandler
functions actually call for an Object
and Delegate
to be passed in (AddressOf
gets compiled into a Delegate
when used), so you don't need the AddressOf
to do what you want, you need a Delegate
.
To do this we can use the CreateDelegate
method which does take a MethodInfo
object. It should be noted that since you're trying to access private methods, you'll need to specify the BindFlags
of Reflection.BindingFlags.Instance
and Reflection.BindFlags.NonPublic
(I say and
but you'll do a bitwise Or
on them), example:
GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
So calling CreateDelegate
on this will give us the following code
[Delegate].CreateDelegate(GetType(Reflection.Assembly), GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic))
But that's rather verbose, so lets break it down:
Dim type As Type = GetType(Reflection.Assembly)
Dim mi As Reflection.MethodInfo = type.GetMethod("ResolveAssembly", (Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic))
And now we can simply call the RemoveHandler
on AppDomain.CurrentDomain.AssemblyResolve
via the following:
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, [Delegate].CreateDelegate(type, mi)
Except AppDomain.CurrentDomain.AssemblyResolve
expects delegate/event signatures to match, so we need to cast our created delegate to the appropriate type:
RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, CType([Delegate].CreateDelegate(type, mi), System.ResolveEventHandler)
And you can now remove a private method through reflection from the event handler.
WARNING!! While this code will compile and run, I make no guarantees of it's validity or accuracy since you're mucking with frame and stack pointers (essentially), and so while it might run and it might work, it also might spawn baby kittens .. so just be careful.
Hope that can help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With