编组C ++指针接口虽然C#函数调用在非默认AppDomain [英] Marshalling C++ pointer interface back though C# function call in a non default AppDomain

查看:408
本文介绍了编组C ++指针接口虽然C#函数调用在非默认AppDomain的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个工作的CLI接口C ++和C#代码之间。代码有一个C ++抽象接口,如:

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();
}

这段代码正确地允许我调用CreateImpl来获得接口的实现包含Start方法。我的问题是,我试图强制整个CLR / .NET加载和执行到不是默认AppDomain的AppDomain。我可以使用下面的代码创建一个辅助AppDomain:

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";
}

每次尝试让工厂返回一个cppns ::此辅助应用程序域中的cppInterface失败。我甚至尝试创建一个二级工厂,它是一个C#类,返回指向实现的接口的指针,以便在大会上的Invoke调用希望使得其余的代码执行在我装载程序集的AppDomain,但Invoke返回一个IDispatch指针,我不能映射回任何类型的C ++指针在我的界面上。

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();;
        }
    };
}

有另外一种方法让所有东西在辅助AppDomain中运行, IDispatch指针可用于调用Start方法?

Is there another way to get everything to run in a secondary AppDomain or is the IDispatch pointer usable in calling the Start method?

推荐答案

我已经设法使大部分的.NET东西在另一个域中运行。看起来没有办法让CLI层在默认AppDomain之外的任何地方运行。

I have managed to get most of the .NET stuff running in another domain. It seems like there is no way to get the CLI layer to run in anything other than the default AppDomain.

为了做这个工作,我需要让这个类两个应用程序派生自MarshalByRefObject。在我上面的例子中,这意味着我不得不改变MyInternalCSharpClass,使它从MarshalByRefObject派生。这也是必要的使从MyInternalCSharpClass发送和返回的对象也从MarshalByRefObject派生。最后,我传递和返回的这些相同的对象必须有[Serializable]属性,并且还将所有的私有变量标记为public。注意,如果通过AppDomains传送的类已经使用Serializable属性,您可以对每个正式的私有变量使用[XmlIgnore],以避免更改正在进行的序列化。

To make this work I needed to make the class that sits within both appdomains derive from MarshalByRefObject. In my example above that meant I had to change MyInternalCSharpClass so that it derived from MarshalByRefObject. It was also nessary to made the objects sent and returned from MyInternalCSharpClass also derive from MarshalByRefObject. Finally I these same objects that were passed and returned had to have the [Serializable] property and to also mark all their private variables public. Note if the classes being transferred though the AppDomains are already using the Serializable attribute you can use [XmlIgnore] on each formally private variable to avoid changing the serialization that is being done.

现在一切都可以在AppDomains之间移动,我通过执行以下操作创建了第二个AppDomain:

Now that everything can be moved between the AppDomains I created a second AppDomain by doing the following:

bool CreateInstanceInAppDomain(const char *pcAppDomainName)
{
    bool bRtn = false;

    gcroot<String^> csStrAppDomainName (gcnew String(pcAppDomainName));
    mAppDomain = AppDomain::CreateDomain(csStrAppDomainName);
    delete csStrAppDomainName;
    Object^ MyInternalObject = mAppDomain->CreateInstanceAndUnwrap("AssemblyName", "ClassNameSpace.MyInternalCSharpClass");
    mInternalClassAccess = dynamic_cast<MyInternalCSharpClass^>(MyInternalObject);
    if (mInternalClassAccess)
    {
        bRtn = true;
    }

    return bRtn;
}

这篇关于编组C ++指针接口虽然C#函数调用在非默认AppDomain的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆