Здравствуйте, Serginio1, Вы писали:
S>В .Net определил интерфейс
S>S>[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
S> public interface ICallback
S> {
S> void execute();
S> }
S>
Нужно явно задать id интерфейса (IID — GuidAttribute)..
S> и реализацию
S>S> HRESULT ICallback::QueryInterface(REFIID riid, void ** ppvObject)
S> {
S> if (!ppvObject)
S> return E_INVALIDARG;
S> *ppvObject = NULL;
S> // if (riid == IID_IUnknown)
S> // {
S> // Increment the reference count and return the pointer.
S> *ppvObject = (LPVOID)this; //тут кастовать нужно к требуемому интерфейсу
S>
return NOERROR;
S>
// }
S>
return E_NOINTERFACE;
S> }
S>
См. выделенное
-ты должен проверять поддерживаемые тобой интерфейсы (как минимум IUnknown)
-и возвращать правильную ссылку на них (с пом. приведения — чтобы получить правильное смещение на vtable)
S> Так вот перед вызовом execute сначала запрашиваеется QueryInterface с двумя riid IUnknown и IProvideClassInfo
S>Если не дать IProvideClassInfo то начинает запрашивать Idispatch и еще какие то интерфейсы.
Ты должен правильно реагировать на эти запросы — реализуешь — возвращай, нет — досвидания, в твоем случае как минимум 2 интерфейса ты поддерживаешь — IUnknown и твой ICallback
Рабочий пример (хост — .net приложение, в случае хостинга как у тебя из нативного приложения результат должен быть такой же)
| нативный код (dll) |
| #include <windows.h>
#include <iostream>
//COM sample
class ICallback : public IUnknown
{
public:
virtual HRESULT __stdcall execute() = 0;
virtual HRESULT __stdcall dispatch(ICallback* other) = 0;
};
extern "C" __declspec(dllexport) ICallback* __stdcall UnmanagedWrapCallback(ICallback* cb);
// {FFB46654-083E-486A-94B8-E28B5C01561D}
static const GUID IID_ICallback =
{ 0xffb46654, 0x83e, 0x486a,{ 0x94, 0xb8, 0xe2, 0x8b, 0x5c, 0x1, 0x56, 0x1d } };
class UnmanagedCallback : public ICallback
{
ULONG _refCount;
ICallback* _other;
public:
UnmanagedCallback(ICallback* other) : _refCount(1), _other(other)
{
std::cout << "ctor UnmanagedCallback" << std::endl;
_other->AddRef();
}
~UnmanagedCallback()
{
std::cout << "dtor UnmanagedCallback" << std::endl;
_other->Release();
}
//IUnknown
HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override
{
OLECHAR* strGuid;
StringFromCLSID(riid, &strGuid);
std::wcout << L"UnmanagedCallback.QueryInterface. Requested IID: " << strGuid << std::endl;
CoTaskMemFree(strGuid);
if (ppvObject == nullptr) return E_INVALIDARG;
if (riid == IID_IUnknown)
{
*ppvObject = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
else if (riid == IID_ICallback)
{
*ppvObject = static_cast<ICallback*>(this);
AddRef();
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
ULONG __stdcall AddRef(void) override
{
std::cout << "UnmanagedCallback.AddRef" << std::endl;
auto cnt = ++_refCount;
return cnt;
}
ULONG __stdcall Release(void) override
{
std::cout << "UnmanagedCallback.Release" << std::endl;
auto cnt = --_refCount;
if (cnt == 0)
{
delete this;
}
return cnt;
}
//ICallback
HRESULT __stdcall execute() override
{
std::cout << "UnmanagedCallback.execute" << std::endl;
_other->execute();
return S_OK;
}
HRESULT __stdcall dispatch(ICallback* other) override
{
std::cout << "UnmanagedCallback.dispatch" << std::endl;
if (other == nullptr) return E_INVALIDARG;
_other->dispatch(other);
return S_OK;
}
};
extern "C" __declspec(dllexport) ICallback* __stdcall UnmanagedWrapCallback(ICallback* other)
{
auto ucb = new UnmanagedCallback(other);
return ucb;
}
|
| |
| ComCallback.cs — .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 реализованна.
| выхлоп |
| Project ComInterop (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Press Enter key to continue...
ManagedCallback.Execute
ctor UnmanagedCallback
UnmanagedCallback.QueryInterface. Requested IID: {00000000-0000-0000-C000-000000000046}
UnmanagedCallback.AddRef
UnmanagedCallback.QueryInterface. Requested IID: {B196B283-BAB4-101A-B69C-00AA00341D07}
UnmanagedCallback.AddRef
UnmanagedCallback.QueryInterface. Requested IID: {ECC8691B-C1DB-4DC0-855E-65F6C551AF49}
UnmanagedCallback.QueryInterface. Requested IID: {94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90}
UnmanagedCallback.QueryInterface. Requested IID: {00000003-0000-0000-C000-000000000046}
UnmanagedCallback.QueryInterface. Requested IID: {00000144-0000-0000-C000-000000000046}
UnmanagedCallback.Release
UnmanagedCallback.QueryInterface. Requested IID: {FFB46654-083E-486A-94B8-E28B5C01561D}
UnmanagedCallback.AddRef
UnmanagedCallback.AddRef
UnmanagedCallback.Release
UnmanagedCallback.Release
UnmanagedCallback.execute
ManagedCallback.Execute
UnmanagedCallback.dispatch
ManagedCallback.Dispatch
ManagedCallback.Execute
UnmanagedCallback.Release
UnmanagedCallback.Release
dtor UnmanagedCallback |
| |