> Is it possible to pass a COM object from unmanaged C++ to C# (and possibly
> back?)
Yes.
> Is yes, what is required in terms of
> - C++ and C# interface declaration
Basically, the same thing you did in your previous post.
> - memory management
Standard COM rules. On the unmanaged side, if you're transferring
ownership to the managed side, nothing special. If you're giving it
its own reference, AddRef the object first. .NET handles refcounting
on the managed side, GC issues etc.
> Any sample would be most helpful.
This is what I used as a test case for your previous thread.
Unmanaged C++ ----------------------------------------
[uuid("a52e9a6f-d286-451d-aaa3-e43b5c182032")]
interface ITest : IUnknown
{
HRESULT __stdcall GetVal(int *i);
HRESULT __stdcall GetReason(VARIANT *pReason);
};
class TestObject : public ITest
{
long m_refCount;
public:
TestObject();
virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
virtual HRESULT __stdcall GetVal(int *i);
virtual HRESULT __stdcall GetReason(VARIANT *pReason);
};
TestObject::TestObject()
{
m_refCount = 1;
}
HRESULT __stdcall TestObject::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if (IsEqualGUID(riid, __uuidof(IUnknown)))
*ppv = static_cast<IUnknown *>(this);
else if (IsEqualGUID(riid, __uuidof(ITestBase)))
*ppv = static_cast<ITestBase *>(this);
else if (IsEqualGUID(riid, __uuidof(ITest)))
*ppv = static_cast<ITest *>(this);
else
return E_NOINTERFACE;
this->AddRef();
return S_OK;
}
ULONG __stdcall TestObject::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
ULONG __stdcall TestObject::Release()
{
long result = InterlockedDecrement(&m_refCount);
if (result == 0)
delete this;
return result;
}
HRESULT __stdcall TestObject::GetVal(int *i)
{
*i = 42;
return S_OK;
}
HRESULT __stdcall TestObject::GetReason(VARIANT *pReason)
{
pReason->vt = VT_BSTR;
pReason->bstrVal = SysAllocString(L"test reason string");
return S_OK;
}
extern "C"
ITest * __stdcall CreateTestObject()
{
TestObject *obj = new TestObject();
return static_cast<ITest *>(obj);
}
------------------------------------------------------
If you haven't seen the interface and [uuid]/__uuidof() stuff before,
it's equivalent to:
struct ITest : public IUnknown
{
virtual HRESULT __stdcall GetVal(int *i) = 0;
virtual HRESULT __stdcall GetReason(VARIANT *pReason) = 0;
};
const IID IID_ITest = { ... }
if IsEqualGUID(riid, &IID_ITest) ...
Just syntactic sugar.
Managed C# -------------------------------------------
using System;
using System.Runtime.InteropServices;
[Guid("a52e9a6f-d286-451d-aaa3-e43b5c182032")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ITest
{
int GetVal();
[PreserveSig] int GetReason(out object reason);
}
class Program
{
[DllImport("VariantTest")]
static extern ITest CreateTestObject();
static void Main()
{
ITest test;
object obj;
Console.Write("trying CreateTestObject... ");
test = CreateTestObject();
Console.WriteLine("succeeded.");
Console.Write("trying ITest::GetVal... ");
Console.WriteLine(test.GetVal());
Console.Write("trying ITest::GetReason... ");
test.GetReason(out obj);
Console.WriteLine(obj);
Console.WriteLine("done");
}
}
------------------------------------------------------
A lot of people recommend Adam Nathan's book, ".NET and COM: The
Complete Interoperability Guide". I'm too cheap to buy books, so I've
never read it, although the code samples are available online:
http://www.samspublishing.com/bookstore/product.asp?isbn=067232170X
(download section at the bottom)
Apress has a book freely available in PDF format, "COM and .NET
Interoperability" by Andrew Troelsen: http://www.apress.com/free/
Hope this helps.