2011-12-06 7 views
7

Unmanaged C++コードからManaged .NETコードを呼び出す方法として、最も優れた方法を探しています。私はC++アプリケーション内で.NETのホスティングに関する情報を見つけました。問題なくpRuntimeHostを作成して起動できます。Managed .NETコードをUnmanagedコードから呼び出す最も良い方法

ExecuteInDefaultAppDomainは実際にはいくつかのパラメータを送信して情報の構造を返すので、非常に制限されているようです。最も明白な選択肢はCOMメソッドを使用することですが、現在のC#コードはメソッドとのインターフェースとして実際には設定されていません。

どちらの方法でも、整数、文字列(char *)、倍精度およびその他のコアC++型を返したいと思います。このC++コードを使用している他のグループは、パフォーマンス上の理由からマネージドコードを使用したくないため、C++をC#に変換するコードが多すぎ、Managed C++を使用することは受け入れられないソリューションです。

既存のC++およびC#コードを可能な限り修正することが目標ですが、C++コードの速度に大きな影響を与えることなく、C++内の特定のポイントでC#コード内のメソッドを使用します。 .NETをホストする、インターネット上で見つけたコードに基づいて

起動とシャットダウンシーケンスは次のとおりです。

#include "stdafx.h" 
#include <metahost.h> 

#pragma comment(lib, "mscoree.lib") 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ICLRMetaHost  *pMetaHost  = NULL; 
    ICLRMetaHostPolicy *pMetaHostPolicy = NULL; 
    ICLRDebugging  *pCLRDebugging = NULL; 

    HRESULT hr; 
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 
    hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy); 
    hr = CLRCreateInstance(CLSID_CLRDebugging, IID_ICLRDebugging, (LPVOID*)&pCLRDebugging); 

    DWORD dwVersion = 0; 
    DWORD dwImageVersion = 0; 
    ICLRRuntimeInfo *pRuntimeInfo; 
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID *)&pRuntimeInfo); 

    ICLRRuntimeHost * pRuntimeHost = NULL; 
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&pRuntimeHost); 

    hr = pRuntimeHost->Start(); 

    DWORD dwRetCode = 0; 
    //hr = pRuntimeHost->ExecuteInDefaultAppDomain(argv[1], L"MyNamespace.MyClass", L"Message", L"Hello World!", &dwRetCode); 

    // Stop the CLR runtime and shutdown cleanly. 
    hr = pRuntimeHost->Stop(); 
    hr = pRuntimeHost->Release(); 
    hr = pRuntimeInfo->Release(); 
    hr = pCLRDebugging->Release(); 
    hr = pMetaHostPolicy->Release(); 
    hr = pMetaHost->Release(); 

    return 0; 
} 

答えて

5

はい、私はジョンに同意します。ランタイムの新しいインスタンスを作成して明示的にホストする必要はありません。最初に、この背後にある配管は十分に文書化されておらず、将来のバージョンで変更される可能性があります。第2に、C++/CLIは、これを最も効率的かつ安全に実行するように設計されています。

  1. 必要な.Net機能を表すネイティブC++インターフェイスを作成します。

  2. umanagedクラスを使用してネイティブインターフェイスを実装するCLRサポートでDLLをセットアップします。実装の内部では、CLR型を作成してアクセスし、gcroot<T>フィールドにインスタンス変数を格納できます。 marshal_asの管理コード/非管理コード、google、またはbingの間を行き来するためにclr interop funcionalityを使用してください。

  3. このコンポーネントのインスタンスを作成する(管理されていない)ファクトリ関数を提供します。この+アンマネージC++インターフェイスは、ネイティブコードに表示されるAPIです。アンマネージdllを使用するのと全く同じ方法でdllを使います。

+0

追加のAppDomainを作成する理由は、C++コードが既定のAppDomainを既にいくつかのものに使用していて、追加の.NETアセンブリを現在のコードに干渉させたくなく、また自分のものが私のものに干渉するのを避けるためです。 BTW私は完全にCLIのレイヤーを管理していますが、私はまだCLIレイヤー全体をデフォルトのAppDomainではない別のAppDomainに取得する方法を見つけようとしています。 –

+0

まだ自分自身でそれを試みたことはありませんが、理論的にはこれは問題ではありません。あなたのシナリオはネイティブのものからマネージドコンポーネントに呼び出すことだと思います。 「スレッドのプロモーション」(googleまたはbing)という機能があり、マネージドコードを最初に実行しようとするたびにネイティブスレッドをマネージドスレッドに昇格させます。 CLRは、AppDomainという管理コードを実行する必要があるという考えを持っていないので、デフォルトの状態にします。したがって、おそらく 'msclr :: call_in_appdomain'ファミリの関数を使用して、その遷移を明示的に処理する必要があります。 –

+0

私はこの場所で私の最終的な解決策を文書化しました:http://stackoverflow.com/questions/10301727/marshalling-c-pointer-interface-back-though-c-sharp-function-call-in-a-non-def –

3

それが許容される場合は、最善の解決策は、インの間に座っている管理C++ DLLを作成することであってもよいです。 Managed C++コードは、管理されたコードとアンマネージコードをブリッジするための最高の/最も効率的な方法です。

実際にはは、COMをミックスに追加したくありません。それは物事をずっと遅くします。

また、管理コードが実際に定量化されないようにするためのこれらの「パフォーマンス上の理由」もありますか?彼らは嫌なことを避けるために投げ捨てられた逸話のように聞こえる。また、がすでにであることを指摘することができます。これは、C#が混在しているためです。

+0

パフォーマンスはマイクロ秒単位でカウントされます。だからこれすべての後に、リクエスト/レスポンスのキャッシュをC++のstd :: mapとして追加しました。これにより、C#レイヤーに戻ることなく以前に要求されたものをすばやく検索することができます。上記の追加情報を添付しました。 –

関連する問題