I have a working CLI interface between C++ and C# code. The code has a C++ abstract interface like:
-------------C++ Interface---------------
namespace cppns
{
class cppInterface
{
public:
virtual bool Start(const char *pcDir) = 0;
};
}
------Implementation of abstract C++ interface in same dll---------
namespace cppns
{
class cppimp : public cppInterface
private:
gcroot<MyInternalCSharpClass^> mInternalClassAccess;
public:
cppimp::cppimp()
{
mInternalClassAccess = gcnew MyInternalCSharpClass();
}
virtual bool cppimp::Start(const char *pcDir)
{
System::AppDomain ^appDom = AppDomain::CurrentDomain::get();
System::String ^strDomainName = appDom->FriendlyName;
mInternalClassAccess->Initalize(pcDir);
}
}
---------Method to create an instance of the class in a factory--------------
cppns::cppInterface *GetImplObject()
{
return new cppns::cppimp();
}
----------Factory class .h to allow C++ to get an instance of the cppimp class------
------The C++ code knows about the abstract interface by including the header file--
------FactoryExport is __declspec(dllexport) when compiled in dll and---------------
----- __declspec(dllimport) when used as a header file in exe that uses header------
class FactoryExport ClassFactory
{
public:
static cppns::cppInterface *CreateImpl();
};
----------Factory class .cpp to allow C++ to get an instance of the cppimp class------
cppns::cppInterface *ClassFactory::CreateImpl()
{
return GetImplObject();
}
This code correctly allows me to call CreateImpl to get an implementation of the interface that contains the Start method. My issue is that I'm trying to force the whole CLR/.NET loading and executing into an AppDomain that is not the default AppDomain. I can create a secondary AppDomain using the following code:
CComPtr<ICorRuntimeHost> pRuntimeHost;
//Retrieve a pointer to the ICorRuntimeHost interface
HRESULT hr = CorBindToRuntimeEx(
L"v2.0.50727", //Retrieve last version before 4.0.
// NULL, //Retrieve latest version by default
L"wks",
STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(void**)&pRuntimeHost.p
);
hr = pRuntimeHost->Start();
DWORD dwAppDomainId = 22;
WCHAR domainName[80 + 1];
swprintf(domainName, 80, L"%s-%ld",L"NoDefaultDomain", dwAppDomainId);
CComPtr<IUnknown> pUnknownAppDomain;
hr = pRuntimeHost->CreateDomainEx(domainName, NULL, NULL, &pUnknownAppDomain);
CComPtr<_AppDomain> pAppDomain;
hr = pUnknownAppDomain->QueryInterface(__uuidof(_AppDomain), (VOID**)&pAppDomain.p);
BSTR bstrFriendlyName;
hr = pAppDomain->get_FriendlyName(&bstrFriendlyName);
if (SUCCEEDED(hr))
{
_bstr_t bstrFriendlyNameWrap(bstrFriendlyName, false);
}
_bstr_t bstrAssemblyName("InteropCode");
CComPtr<_Assembly> pAssembly;
hr = pAppDomain->Load_2(bstrAssemblyName, &pAssembly);
BSTR bstrFullName;
hr = pAssembly->get_FullName(&bstrFullName);
if (SUCCEEDED(hr))
{
_bstr_t bstrFullNameWrap(bstrFullName, false);
std::cout << "Assembly name is: " << bstrFullNameWrap << "\n";
}
Every attempt of getting the factory to return to me an interface to cppns::cppInterface within this secondary application domain has failed. I have even attempted to create a secondary factory that is a C# class that returns the pointer to the implemented interface so that an Invoke call on the Assembly would hopefully cause the rest of the code to execute in the AppDomain that I loaded the Assembly into but the Invoke returns an IDispatch pointer that I can't seem to map back into any type of C++ pointer on my interface.
namespace cppns
{
public ref class NetFactory
{
public:
NetFactory()
{
}
cppInterface *CreateInterop()
{
return GetImplObject();;
}
};
}
Is there another way to get everything to run in a secondary AppDomain or is the IDispatch pointer usable in calling the Start method?