_>>Здравствуйте, Serginio1, Вы писали:
S>>>Попробовал с VMT
S>>>Определил методы
_>>Вот ты неуемный ты бы для начала проверил, работает ли COM-интероп на linux — ведь это же твоя цель?
_>>И если работает — тему можно закрывать, COM-интеропа тебе хватит за глаза.
_>>Или ты заради любви к искусству?
S> И то и другое. Да ине нужны мне методы IUknown. Я итак передаю нужныю ссылку, а подсчет ссылок если мне нужно организую сам.
S> Для приведения к интерфейсу при вызове одного метода идет куча QueryInterface Addref,Release
S>http://rsdn.org/forum/dotnet/6611240.1Автор: pilgrim_
Дата: 15.11.16
Ну ежели упорный, вот смотри примерный вариант ручного маршалинга, а затем сравни его с
автоматическимАвтор: pilgrim_
Дата: 15.11.16
(не забывая про разные C++ ABI)
| C++ native не-COM интерфейс |
| #include <stdio.h>
#include <cassert>
class ICallbackNotCom
{
public:
virtual bool __stdcall release() = 0;
virtual bool __stdcall execute() = 0;
virtual bool __stdcall dispatch(ICallbackNotCom* other) = 0;
};
static void trace(const char* message)
{
fprintf(stderr, "%s\n", message);
//std::cout << message << std::endl;
}
class UnmanagedCallbackNotCom : public ICallbackNotCom
{
static constexpr const char* Signature = "INTEROP";
ICallbackNotCom* _other;
const char* _sig;
private:
void CheckSignature() const
{
assert(_sig == Signature);
}
public:
UnmanagedCallbackNotCom(ICallbackNotCom* other) : _other(other)
{
trace("ctor UnmanagedCallbackNotCom");
_sig = Signature;
}
~UnmanagedCallbackNotCom()
{
CheckSignature();
trace("dtor UnmanagedCallbackNotCom");
}
//ICallbackNotCom
bool __stdcall release() override
{
CheckSignature();
trace("UnmanagedCallbackNotCom.release");
delete this;
return true;
}
bool __stdcall execute() override
{
CheckSignature();
trace("UnmanagedCallbackNotCom.execute");
_other->execute();
return true;
}
bool __stdcall dispatch(ICallbackNotCom* other) override
{
CheckSignature();
trace("UnmanagedCallbackNotCom.dispatch");
if (other == nullptr) return false;
_other->dispatch(other);
return true;
}
};
extern "C" __declspec(dllexport) ICallbackNotCom* __stdcall UnmanagedWrapCallbackNotCom(ICallbackNotCom* other)
{
auto ucb = new UnmanagedCallbackNotCom(other);
return ucb;
}
|
| |
| C# .NET хост — ручной маршалинг интерфейсов в натив и обратно |
|
class Program
{
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();
}
}
[StructLayout(LayoutKind.Sequential)]
public class NativeCallbackShim
{
[StructLayout(LayoutKind.Sequential)]
public sealed class Vtbl
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool ReleaseHandler(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool ExecuteHandler(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool DispatchHandler(IntPtr self, IntPtr other);
//GCC (Itanium ABI) specific
//public IntPtr VTableEntry0;
//public IntPtr VTableEntry1;
public ReleaseHandler Release;
public ExecuteHandler Execute;
public DispatchHandler Dispatch;
}
protected IntPtr _vtblPtr;
protected NativeCallbackShim()
{
}
public NativeCallbackShim(IntPtr thisPtr)
{
var iface = Marshal.PtrToStructure<NativeCallbackShim>(thisPtr);
_vtblPtr = iface._vtblPtr;
}
public static Vtbl GetVtbl(IntPtr thisPtr)
{
var iface = Marshal.PtrToStructure<NativeCallbackShim>(thisPtr);
var vtbl = iface.GetVtbl();
return vtbl;
}
public Vtbl GetVtbl() => Marshal.PtrToStructure<Vtbl>(_vtblPtr);
}
public sealed class NativeCallback : ICallback, IDisposable
{
private IntPtr _nativeCallbackPtr;
private readonly NativeCallbackShim.Vtbl _vtbl;
public NativeCallback(IntPtr callbackPtr)
{
_nativeCallbackPtr = callbackPtr;
_vtbl = NativeCallbackShim.GetVtbl(callbackPtr);
}
public void Execute()
{
CheckDisposedState();
_vtbl.Execute(_nativeCallbackPtr);
}
public void Dispatch(ICallback other)
{
CheckDisposedState();
using (var shim = new Managed2NativeCallbackShim(other))
{
_vtbl.Dispatch(_nativeCallbackPtr, shim.ToPointer());
}
}
public void Dispose()
{
if (_nativeCallbackPtr != IntPtr.Zero)
{
_vtbl.Release(_nativeCallbackPtr);
_nativeCallbackPtr = IntPtr.Zero;
}
}
private void CheckDisposedState()
{
if (_nativeCallbackPtr == IntPtr.Zero)
{
throw new ObjectDisposedException(nameof(NativeCallback));
}
}
}
[StructLayout(LayoutKind.Sequential)]
public sealed class Managed2NativeCallbackShim : NativeCallbackShim, ICallback, IDisposable
{
[StructLayout(LayoutKind.Sequential)]
private struct NativeInterfaceShim
{
public IntPtr vtblPtr;
}
private readonly Vtbl _vtbl; //note: keep reference to vtbl!
private IntPtr _thisPtr;
private readonly ICallback _callback;
public Managed2NativeCallbackShim(ICallback cb)
{
_callback = cb;
//note: keep reference to vtbl!
_vtbl = new Vtbl
{
Release = _ => true,
Execute = _ =>
{
Execute();
return true;
},
Dispatch = (_, other) =>
{
Dispatch(new NativeCallback(other));
return true;
}
};
var vtblSize = Marshal.SizeOf(_vtbl);
_vtblPtr = Marshal.AllocHGlobal(vtblSize);
Marshal.StructureToPtr(_vtbl, _vtblPtr, false);
}
public IntPtr ToPointer()
{
CheckDisposedState();
if (_thisPtr == IntPtr.Zero)
{
var shim = new NativeInterfaceShim { vtblPtr = _vtblPtr};
_thisPtr = Marshal.AllocHGlobal(Marshal.SizeOf(shim));
Marshal.StructureToPtr(shim, _thisPtr, false);
}
return _thisPtr;
}
public void Execute()
{
CheckDisposedState();
_callback.Execute();
}
public void Dispatch(ICallback other)
{
CheckDisposedState();
_callback.Dispatch(other);
}
public void Dispose()
{
if (_thisPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_thisPtr);
_thisPtr = IntPtr.Zero;
}
if (_vtblPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_vtblPtr);
_vtblPtr = IntPtr.Zero;
}
}
private void CheckDisposedState()
{
if (_vtblPtr == IntPtr.Zero)
{
throw new ObjectDisposedException(nameof(Managed2NativeCallbackShim));
}
}
}
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
static extern IntPtr UnmanagedWrapCallbackNotCom(IntPtr callback);
static void Main()
{
Console.WriteLine("Press Enter key to continue...");
//Console.ReadLine();
TestNotComCallback();
}
static void TestNotComCallback()
{
var managedCallback = new ManagedCallback();
var managedCallbackShim = new Managed2NativeCallbackShim(managedCallback);
managedCallbackShim.Execute();
var nativeCallbackPtr = UnmanagedWrapCallbackNotCom(managedCallbackShim.ToPointer());
var nativeCallback = new NativeCallback(nativeCallbackPtr);
try
{
nativeCallback.Execute();
nativeCallback.Dispatch(managedCallbackShim);
nativeCallback.Dispatch(nativeCallback);
}
finally
{
managedCallbackShim.Dispose();
nativeCallback.Dispose();
}
GC.KeepAlive(managedCallbackShim);
}
}
|
| |
| выхлоп |
| Project NotComInterop (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Press Enter key to continue...
ManagedCallback.Execute
ctor UnmanagedCallbackNotCom
UnmanagedCallbackNotCom.execute
ManagedCallback.Execute
UnmanagedCallbackNotCom.dispatch
ManagedCallback.Dispatch
ManagedCallback.Execute
UnmanagedCallbackNotCom.dispatch
ManagedCallback.Dispatch
UnmanagedCallbackNotCom.execute
ManagedCallback.Execute
UnmanagedCallbackNotCom.release
dtor UnmanagedCallbackNotCom |
| |