Здравствуйте, Serginio1, Вы писали:
α>>В мсдн пишут что в принципе можно, но саму структуру классов с++ надо заранее проектировать под интеграцию с .net. Для остальных случаев рекомендуют оборачивать общение с классами с++ в с-api
S> Мне как раз и нужно вызывать нативные методы из .Net
Здравствуйте, Lexey, Вы писали:
L>Здравствуйте, Serginio1, Вы писали:
S>> Так суть COM это VMT. А она по сути кроссплатформенна.
L>С каких это пор реализации VMT стали кроссплатформенными? http://rsdn.org/forum/dotnet/6608772.1
Здравствуйте, α, Вы писали:
α>Здравствуйте, Serginio1, Вы писали:
α>>>В мсдн пишут что в принципе можно, но саму структуру классов с++ надо заранее проектировать под интеграцию с .net. Для остальных случаев рекомендуют оборачивать общение с классами с++ в с-api
S>> Мне как раз и нужно вызывать нативные методы из .Net
α>Всё равно все сводится к соответствующей подготовке кода на С++ к interop/pinvoke. А это либо как уже тут сказали — COM, либо обертка в виде С-plain-API, либо вот такие фокусы — https://blogs.msdn.microsoft.com/vcblog/2008/12/08/inheriting-from-a-native-c-class-in-c/
Это видел. Решил поэксперементировать.
В .Net определил интерфейс
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICallback
{
void execute();
}
и сделал статический метод
public static void CallInterface(ICallback cb)
{
cb.execute();
}
Здравствуйте, Serginio1, Вы писали:
S> В С++ определил класс S>class ICallback : public IUnknown
А упорядочить методы тут разве не надо? Т.е. сперва методы IUnknown, потом твой execute(). Что-то я уже подзабыл
PS А, это ж класс, а не интерфейс. Перепутал
Здравствуйте, α, Вы писали:
α>Здравствуйте, Serginio1, Вы писали:
S>> В С++ определил класс S>>class ICallback : public IUnknown
α>А упорядочить методы тут разве не надо? Т.е. сперва методы IUnknown, потом твой execute(). Что-то я уже подзабыл α>PS А, это ж класс, а не интерфейс. Перепутал
См. выделенное
-ты должен проверять поддерживаемые тобой интерфейсы (как минимум IUnknown)
-и возвращать правильную ссылку на них (с пом. приведения — чтобы получить правильное смещение на vtable) S> Так вот перед вызовом execute сначала запрашиваеется QueryInterface с двумя riid IUnknown и IProvideClassInfo S>Если не дать IProvideClassInfo то начинает запрашивать Idispatch и еще какие то интерфейсы.
Ты должен правильно реагировать на эти запросы — реализуешь — возвращай, нет — досвидания, в твоем случае как минимум 2 интерфейса ты поддерживаешь — IUnknown и твой ICallback
Рабочий пример (хост — .net приложение, в случае хостинга как у тебя из нативного приложения результат должен быть такой же)
class Program
{
#region COM interop
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("FFB46654-083E-486A-94B8-E28B5C01561D")]
public interface ICallback
{
void Execute();
void Dispatch(ICallback other);
}
public class ManagedCallback : ICallback
{
public void Execute()
{
Console.WriteLine($"{nameof(ManagedCallback)}.{nameof(Execute)}");
}
public void Dispatch(ICallback other)
{
Console.WriteLine($"{nameof(ManagedCallback)}.{nameof(Dispatch)}");
other.Execute();
}
}
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
private static extern ICallback UnmanagedWrapCallback(ICallback cb);
#endregion COM interop
static void Main()
{
Console.WriteLine("Press Enter key to continue...");
//Console.ReadLine();
TestComCallback();
}
static void TestComCallback()
{
var mcb = new ManagedCallback();
mcb.Execute();
WrapUnmanaged(mcb);
}
static void WrapUnmanaged(ICallback cb)
{
var ucb = UnmanagedWrapCallback(cb);
try
{
ucb.Execute();
ucb.Dispatch(cb);
}
finally
{
Marshal.ReleaseComObject(ucb);
}
}
}
Проверил на .NET Core dotnet-dev-win-x86.1.0.0-preview2-003131 — все работает как и в "большом" .NET, значит как минимум для windows поддержка COM-interop реализованна.
Здравствуйте, ajanov, Вы писали:
A>Здравствуйте, Serginio1, Вы писали:
S>> Возможно ли вызвать виртуальные методы С++ классов из .Net Core.
S>> Да и как там в .Net Core C++/CLI ?
A>Компилятор C++/CLI берет все заботы на себя
А какие опции под .Net Core? Просто я в С++ новичок
и солнце б утром не вставало, когда бы не было меня
Re[3]: .Net Core Вызов виртуальных методов нативных объектов
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, ajanov, Вы писали:
A>>Здравствуйте, Serginio1, Вы писали:
S>>> Возможно ли вызвать виртуальные методы С++ классов из .Net Core.
S>>> Да и как там в .Net Core C++/CLI ?
A>>Компилятор C++/CLI берет все заботы на себя
S> А какие опции под .Net Core? Просто я в С++ новичок
Не заметил, что про .Net Core речь идет Прошу прощения. Боюсь, что и про C++/CLI наврал
Re[4]: .Net Core Вызов виртуальных методов нативных объектов
Если все как в .Net Framework — то вперед, даже существующие библиотеки не нужно адаптировать, чтобы их использовать в .Net. В C++ проекте настройку General->Common Language Runtime support нужно установить в Common Language Runtime Support (/clr). Полезный раздел о поддержке .Net в C++: https://msdn.microsoft.com/en-us/library/68td296t(v=vs.140).aspx
Re[6]: .Net Core Вызов виртуальных методов нативных объектов
A>Если все как в .Net Framework — то вперед, даже существующие библиотеки не нужно адаптировать, чтобы их использовать в .Net. В C++ проекте настройку General->Common Language Runtime support нужно установить в Common Language Runtime Support (/clr). Полезный раздел о поддержке .Net в C++: https://msdn.microsoft.com/en-us/library/68td296t(v=vs.140).aspx
Здравствуйте, ajanov, Вы писали:
A>Десиплюсплюсизация от Майкрософт
У C++/CLI столько тараканов, что лучше иметь нормальный ABI (C-like API), чем писать костыли. А для библиотек которые header/template based всё равно только топор поможет. Топором в этом случае я имею ввиду вынос части своей логики в C++ который и сможет быть и скомпилирован эффективно, и вызван (ну и работа будет делаться с минимумом пересечений managed-native границ). Микс же и прозрачные "трамплины" скорости не добавят, в поддержке сложнее, доп знания о диалекте и энвайронменте опять же нужны.
Ну на вскидку — прийдется хорошенько попрыгать прежде чем нативный колбэк будет вызывать код в правильном апп домене, в то время как в интеропе со стороны шарпа (через делегаты и GetFunctionPointer) это достанется бесплатно. Понятно, что всё тоже можно замутить в C++/CLI, но легче из шарпа работать с любыми типами. Лиж бы описания структур были, а потом указатель и вперёд. Но это как раз об ABI.
Re[9]: .Net Core Вызов виртуальных методов нативных объектов
Здравствуйте, fddima, Вы писали:
F> Ну на вскидку — прийдется хорошенько попрыгать прежде чем нативный колбэк будет вызывать код в правильном апп домене, в то время как в интеропе со стороны шарпа (через делегаты и GetFunctionPointer) это достанется бесплатно. Понятно, что всё тоже можно замутить в C++/CLI, но легче из шарпа работать с любыми типами. Лиж бы описания структур были, а потом указатель и вперёд. Но это как раз об ABI.
А можно поподробнее про ABI. Нашел только http://stackoverflow.com/questions/3784389/difference-between-api-and-abi
и солнце б утром не вставало, когда бы не было меня
Re[10]: .Net Core Вызов виртуальных методов нативных объекто
Здравствуйте, Serginio1, Вы писали:
S> А можно поподробнее про ABI. Нашел только http://stackoverflow.com/questions/3784389/difference-between-api-and-abi
Так там же ж вполне понятно написано. Под ABI понимается любое стабильное соглашение о том как программы взаимодействуют на бинарном уровне. COM в частности — это универсальный такой контракт (интерфейс). Они могут быть и специализированными. Все в итоге выливается в набор экспортируемых вызовов из динамической библиотеки, описания структур и желательно механизм валидации определения версий.
Понятно что для реализации этого нам необходимо предоставить C-like интерфейс, а в дотнете просто юзать PInvoke, при этом мы опускаем остальные детали т.к. обе среды остальное делают за нас (соглашение вызовов, упаковка/выравниевание структур и т.п.).
В том же CEF, например, для того что бы создать объект (реализуемый на стороне C#), я заполняю таблицу с адресами методов которые реализуют конкретные функции, что-то вроде VMT, но на каждый объект своя таблица. А при потреблении объектов — беру адрес функции, делегат и вперед вызывать. Т.е. тонны экспортов из dll нет.
Это и есть "наше" соглашение, используемое для:
1. построения этого самого слоя ABI, т.е. способ которым библиотека экспортирует свой функционал в виде динамической библиотеки (полностью автоматически).
2. построения клиента (C++) для библиотеки (т.е. API внешне выставляется такой же как и "внутри", но на самом деле там самый настоящий интероп с маршаллингом, например, с передачей строк по значению, ну и по ссылке когда надо) (полностью автоматически).
3. построения биндингов для (C#, Go, Python с той или иной степенью автоматизации), но не вокруг этой клиентской C++ обертки, а вокруг этого самого ABI. При этом, разумеется, выпуск патчей не ломает совместимость, хотя такой халявы как в дотнете с символическим связыванием — увы нет — метаданных то нет. Есть один идентификатор (хэш) — если не совпадает — значит другая версия ABI и работать с ней нельзя.
Механизм в целом тот ещё, но по факту довольно удобен, даж Servo к себе на вооружение взяли. Но это ж для демонстрации.
PS: Я возможно не верно понял, чего ты там не понял, или куда ещё подробнее?
UPD2: У WebKit2 на мой взгляд вменяемый интерфейс в этом плане, но правда не без своих таракашек, как и везде.
UPD3: Один из ответов на SO гласит:
ABI: Application Binary Interface
This is how the compiler builds an application.
It defines things (but is not limited to):
— How parameters are passed to functions (registers/stack).
— Who cleans parameters from the stack (caller/callee).
— Where the return value is placed for return.
— How exceptions propagate.
Конечно же это не так (это далеко не всё). Описанное — это соглашение вызова функции (call convention). Соглашение по исключениям... хм, а они есть / могут быть? Да даже C/C++ библиотеки имеют ABI, тот же libc которому следует компилятор (и может таргетиться на разные версии), дабы обеспечить максимальную совместимость. Ну т.е. на уровне того, чего именно финальный экзешник потребляет (в терминах импортов ну и связанных вещей, стуктуры, соглашение вызова и т.п.).
API же — это скорее то, что предоставляет библиотека, и как мы её потребляем в той или иной среде. API например может содержать 2 метода, однако на уровне ABI это будет один метод с параметром.
Так суть интерфейса это VMT. А классы с виртуальными методами кроссплатформенны.
В 1С это прекрасно работает
class IInitDoneBase
{
public:
virtual ~IInitDoneBase() {}
/// Initializes component
/**
* @param disp - 1C:Enterpise interface
* @return the result of
*/virtual bool ADDIN_API Init(void* disp) = 0;
/// Sets the memory manager
/*
* @param mem - pointer to memory manager interface.
* @return the result of
*/virtual bool ADDIN_API setMemManager(void* mem) = 0;
/// Returns component version
/**
* @return - component version (2000 - version 2)
*/virtual long ADDIN_API GetInfo() = 0;
/// Uninitializes component
/**
* Component here should release all consumed resources.
*/virtual void ADDIN_API Done() = 0;
};
///////////////////////////////////////////////////////////////////////////
/**
* The given interface defines methods that are intented to be used by the Platform
*/
/// Interface describing extension of language.