Ответ 1
По моему опыту предложение хакана не работает. Вот что я делаю.
Результат показывает, что прикрепленный обработчик является членом объекта, на который указывает _target
. Сбрасывая это, вы получите таблицу методов.
Я построил аналогичный пример, чтобы проиллюстрировать:
0:000> !do 02844de4
Name: System.EventHandler
MethodTable: 0067afa4
EEClass: 0052ef88
Size: 32(0x20) bytes
(C:\windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
002e6d58 40000ff 4 System.Object 0 instance 02842d20 _target
0058df70 4000100 8 ...ection.MethodBase 0 instance 00000000 _methodBase
0058743c 4000101 c System.IntPtr 1 instance 2cc060 _methodPtr
0058743c 4000102 10 System.IntPtr 1 instance 0 _methodPtrAux
002e6d58 400010c 14 System.Object 0 instance 00000000 _invocationList
0058743c 400010d 18 System.IntPtr 1 instance 0 _invocationCount
В этом случае я посмотрю на объект в 02842d20
.
0:000> !do 02842d20
Name: app.Foo
MethodTable: 002c30bc
EEClass: 002c13d4
Size: 12(0xc) bytes
(C:\workspaces\TestBench\app\bin\x86\Debug\app.exe)
Fields:
None
Таким образом, тип цели app.Foo
. Пусть дамп методы для этого типа.
0:000> !dumpmt -md 002c30bc
EEClass: 002c13d4
Module: 002c2c5c
Name: app.Foo
mdToken: 02000002 (C:\workspaces\TestBench\app\bin\x86\Debug\app.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 6
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
002ec015 002e6cbc NONE System.Object.ToString()
002ec019 002e6cc4 NONE System.Object.Equals(System.Object)
002ec029 002e6cf4 NONE System.Object.GetHashCode()
005f4930 002e6d1c JIT System.Object.Finalize()
005f8238 002c30b4 JIT app.Foo..ctor()
005f8270 002c30a8 JIT app.Foo.Bar(System.Object, System.EventArgs)
Сравните значения таблицы MethodDesc
с исходным значением _methodPtr
. Нет очевидного соответствия.
_methodPtr указывает на фрагмент кода, который либо делает jmp
на адрес рассматриваемой функции, либо вызывает процедуру исправления, поэтому следующим шагом будет использование команды !u
для значения _methodPtr
. Если мы видим инструкцию jmp
, у нас есть адрес и с помощью !u
на этом мы получаем метод.
Если, с другой стороны, мы видим a call
to clr!PrecodeFixupThunk
, мы можем получить MethodDesc, сбросив память, на которую указывает _methodPtr
, как этот
0:000> dd 2cc060
002cc060 7e5d65e8 00005e6e 002c30a8 00000000
002cc070 00000000 00000000 00000000 00000000
002cc080 00000000 00000000 00000000 00000000
мы видим что-то похожее на запись таблицы методов в качестве третьего DWORD. Сравнивая значение 002c30a8
с таблицей методов выше, мы видим, что имя метода app.Foo.Bar
.
Так как это построенный пример, я знаю, что нашел метод, который я искал в этом случае.
На самом деле это может быть немного сложнее, чем показано в приведенном выше примере, поскольку поля используются по-разному в зависимости от фактического использования события. Однако, по моему опыту, вышеприведенный подход будет работать в общем сценарии издателя/подписчика.
Подробнее о деталях реализации смотрите в файле comdelegate.cpp
CLI общего источника.