2012-04-24 12 views
2

私はC++コードとC#コードの間に動作するCLIインターフェイスを持っています。このコードは正しく私はStartメソッドが含まれているインタフェースの実装を取得するためにCreateImplを呼び出すことができますデフォルトのAppDomain以外のC#関数呼び出しを使ってC++ポインタインターフェイスを整理する

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

:コードは次のようにC++抽象インタフェースを持っています。私の問題は、CLR/.NET全体のロードと実行をデフォルトのAppDomainではないAppDomainに強制しようとしていることです。私は、次のコードを使用して、二次のAppDomainを作成することができます。

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は私のインターフェイス上の任意のタイプのC++ポインタにマップすることができないIDispatchポインタを返します。

namespace cppns 
{ 
    public ref class NetFactory 
    { 
    public: 
     NetFactory() 
     { 
     } 

     cppInterface *CreateInterop() 
     { 
      return GetImplObject();; 
     } 
    }; 
} 

セカンダリAppDomainですべてを実行する別の方法、またはStartメソッドを呼び出す際に使用できるIDispatchポインターはありますか?

答えて

1

私は、他のドメインで実行されている.NETの大部分を手に入れることができました。デフォルトのAppDomain以外でCLIレイヤを実行する方法がないようです。

この作業をするには、両方のappdomain内にあるクラスをMarshalByRefObjectから派生させる必要がありました。上の私の例では、MarshalByRefObjectから派生するようにMyInternalCSharpClassを変更する必要がありました。また、MyInternalCSharpClassから返されたオブジェクトをMarshalByRefObjectから派生させることも必要でした。最後に、渡され返されたこれらの同じオブジェクトは、[Serializable]プロパティを持っていなければなりません。 AppDomainsを介して転送されるクラスがすでにSerializable属性を使用している場合は、各正式なプライベート変数で[XmlIgnore]を使用して、実行中のシリアル化を変更しないようにすることができます。

今、すべては、私は次の操作を行って、第二のAppDomainを作成したのAppDomain間を移動できること:

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; 
} 
関連する問題