Сообщение Re[13]: .Net Core Вызов виртуальных методов нативных объекто от 18.11.2016 10:29
Изменено 18.11.2016 10:32 Serginio1
Здравствуйте, fddima, Вы писали:
Попробовал с VMT
Определил методы
Создал функцию для получения адреса метода
Для интерфеса вроде работает
Надо будет с параметрами проверить.
Но вот с ThisCall проблема.
Определил класс
и метод
В .Net
И вызов
Вот при вызове CallInterface2
параметры поменяны местами, а переданное первым параметром значение не соотвествует переданному.
Сейчас проверю без __stdcall , но чего то маловато CallingConvention
Попробовал с VMT
Определил методы
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void ВиртуальныйМетодОбъектаСDelegate(IntPtr self, int Число);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
internal delegate void ВиртуальныйМетодОбъекта2Delegate(IntPtr self, int Число1, int Число2);Создал функцию для получения адреса метода
public static IntPtr ПолучитьАдресВиртуальногоМетода(IntPtr Объект, int ИндексВТаблицеВиртуальныхМетодов )
{
int размерIntPtr = Marshal.SizeOf<IntPtr>();
// Первым полем объекта идет ссылка на VMT
// Прочитаем её
var АдресVMT = Marshal.ReadIntPtr(Объект);
// получим адресс метода по смещению в VMT
var АдресМетодаVMT = АдресVMT + ИндексВТаблицеВиртуальныхМетодов * размерIntPtr;
var АдресМетода = Marshal.ReadIntPtr(АдресМетодаVMT);
return АдресМетода;
}Для интерфеса вроде работает
public static void CallInterface(IntPtr cb)
{
var cb2 = Marshal.GetObjectForIUnknown(cb) as ICallback;
cb2?.execute(555);
// метод execute в VMT идет 4 (QueryInterface,Addref,Release)
// а индекс равен 3
var АдресМетода = ПолучитьАдресВиртуальногоМетода(cb,3);
// Получим делегат по дресу
var execute = Marshal.GetDelegateForFunctionPointer<ВиртуальныйМетодОбъектаСDelegate>(АдресМетода);
// И вызовем метод
execute(cb, 666);
}Надо будет с параметрами проверить.
Но вот с ThisCall проблема.
Определил класс
struct TestThisCall {
public:
virtual void __stdcall execute(int value1, int value2);
};
typedef void(STDMETHODCALLTYPE *ManagedRunCallback2)(TestThisCall*);и метод
void TestThisCall::execute(int value1, int value2)
{
wprintf_s(L"sizeof(int) %d\n", sizeof(int));
wprintf_s(L"TestThisCall from.Net value1 %d\n", value1);
wprintf_s(L"Adress this %d\n", this);
wprintf_s(L"TestThisCall from.Net value2 %d\n", value2);
}В .Net
public static void CallInterface2(IntPtr ttc)
{
var АдресМетода = ПолучитьАдресВиртуальногоМетода(ttc, 0);
// Получим делегат по дресу
var execute = Marshal.GetDelegateForFunctionPointer<ВиртуальныйМетодОбъекта2Delegate>(АдресМетода);
// И вызовем метод
execute(ttc, ttc.ToInt32(), 777);
}И вызов
ManagedRunCallback pRunCallback;
ManagedRunCallback2 pRunCallback2;
if (!CreateDelegate(domainId, L"CallInterface", (INT_PTR*)&pRunCallback)) return false;
if (!CreateDelegate(domainId, L"CallInterface2", (INT_PTR*)&pRunCallback2)) return false;
ICallback* cb = new ICallback();
pRunCallback(cb);
TestThisCall* ttc = new TestThisCall();
pRunCallback2(ttc);Вот при вызове CallInterface2
параметры поменяны местами, а переданное первым параметром значение не соотвествует переданному.
Сейчас проверю без __stdcall , но чего то маловато CallingConvention
Re[13]: .Net Core Вызов виртуальных методов нативных объекто
Здравствуйте, fddima, Вы писали:
Попробовал с VMT
Определил методы
Создал функцию для получения адреса метода
Для интерфеса вроде работает
Надо будет с параметрами проверить.
Но вот с ThisCall проблема.
Определил класс
и метод
В .Net
И вызов
Вот при вызове CallInterface2
параметры поменяны местами, а переданное первым параметром значение не соотвествует переданному.
Сейчас проверю без __stdcall , но чего то маловато CallingConvention
Да если убрать __stdcall то все работает правильно.
Попробовал с VMT
Определил методы
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void ВиртуальныйМетодОбъектаСDelegate(IntPtr self, int Число);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
internal delegate void ВиртуальныйМетодОбъекта2Delegate(IntPtr self, int Число1, int Число2);Создал функцию для получения адреса метода
public static IntPtr ПолучитьАдресВиртуальногоМетода(IntPtr Объект, int ИндексВТаблицеВиртуальныхМетодов )
{
int размерIntPtr = Marshal.SizeOf<IntPtr>();
// Первым полем объекта идет ссылка на VMT
// Прочитаем её
var АдресVMT = Marshal.ReadIntPtr(Объект);
// получим адресс метода по смещению в VMT
var АдресМетодаVMT = АдресVMT + ИндексВТаблицеВиртуальныхМетодов * размерIntPtr;
var АдресМетода = Marshal.ReadIntPtr(АдресМетодаVMT);
return АдресМетода;
}Для интерфеса вроде работает
public static void CallInterface(IntPtr cb)
{
var cb2 = Marshal.GetObjectForIUnknown(cb) as ICallback;
cb2?.execute(555);
// метод execute в VMT идет 4 (QueryInterface,Addref,Release)
// а индекс равен 3
var АдресМетода = ПолучитьАдресВиртуальногоМетода(cb,3);
// Получим делегат по дресу
var execute = Marshal.GetDelegateForFunctionPointer<ВиртуальныйМетодОбъектаСDelegate>(АдресМетода);
// И вызовем метод
execute(cb, 666);
}Надо будет с параметрами проверить.
Но вот с ThisCall проблема.
Определил класс
struct TestThisCall {
public:
virtual void __stdcall execute(int value1, int value2);
};
typedef void(STDMETHODCALLTYPE *ManagedRunCallback2)(TestThisCall*);и метод
void TestThisCall::execute(int value1, int value2)
{
wprintf_s(L"sizeof(int) %d\n", sizeof(int));
wprintf_s(L"TestThisCall from.Net value1 %d\n", value1);
wprintf_s(L"Adress this %d\n", this);
wprintf_s(L"TestThisCall from.Net value2 %d\n", value2);
}В .Net
public static void CallInterface2(IntPtr ttc)
{
var АдресМетода = ПолучитьАдресВиртуальногоМетода(ttc, 0);
// Получим делегат по дресу
var execute = Marshal.GetDelegateForFunctionPointer<ВиртуальныйМетодОбъекта2Delegate>(АдресМетода);
// И вызовем метод
execute(ttc, ttc.ToInt32(), 777);
}И вызов
ManagedRunCallback pRunCallback;
ManagedRunCallback2 pRunCallback2;
if (!CreateDelegate(domainId, L"CallInterface", (INT_PTR*)&pRunCallback)) return false;
if (!CreateDelegate(domainId, L"CallInterface2", (INT_PTR*)&pRunCallback2)) return false;
ICallback* cb = new ICallback();
pRunCallback(cb);
TestThisCall* ttc = new TestThisCall();
pRunCallback2(ttc);Вот при вызове CallInterface2
параметры поменяны местами, а переданное первым параметром значение не соотвествует переданному.
Сейчас проверю без __stdcall , но чего то маловато CallingConvention
Да если убрать __stdcall то все работает правильно.