2009-10-28 9 views
7

私はのDLLの何百もの巨大な(主に)C++/MFCアプリケーションで作業(アンマネージド)C++

[これは...申し訳ありません... TLDRを取得しています] ; COMを介して動的にロードされる「アドイン」メカニズムをサポートするため、COM相互運用機能を使用して.NETでアドインを開発することができます。この「アドイン」メカニズム(ただし、動的にロードされていますが)を使用しないで、一部の新機能が.NETで開発されました。ただし、エンドユーザーはこの機能を使用しないことを決定できます。したがって、起動時に.NETがロードされないことがあります。

しかし、.NET は、私はいくつかの.NET固有initialzationを行う必要があり、ロードされたときに(特にネイティブ/非管理UIに一致するようにCurrentUICultureのを設定)。

解決策の1つは、コードが新しい.NET機能またはCOMアドインのいずれかを読み込むようになったときに、この.NET初期化を単純に行い、実行することです。このアプリケーションの性質を考えると、おそらく95 +%のソリューションです(ほとんどのユーザーは新しい機能を使用します)。

しかし、それは絶対確実ではありません。 /clrフラグ(これは巨大なアプリケーションであることを覚えておいてください)を持つモジュールを構築することで、いつでも新しい.NET機能を簡単に追加できます。

もうひとつの堅牢な(明らかな)解決策は、C++/CLIを使って起動時に.NETをロードすることです。しかし、すべてのバイトとクロックのサイクルが関係しているダイハードのC++開発者の中には、これをしたくないものもあります。 CurrentUICultureを設定する必要がないため、.NETがロードされていない限り、若干理解できます。

私が考えた別の可能性は、LoadLibraryをフックしてmscorlibを探すことです。今私は.NETが何らかの理由でロードされようとしていることを知り、通常の方法でロードし、他のコードが何もしないうちに初期化を行います。しかし、フックLoadLibrary(またはそれに関しては他のもの)は本当に私がやりたいことではありません。

.NETの読み込みを容易にする方法はありますか?

編集:LockClrVersionリードの答えはかなりくそ近くにあります。唯一の問題は、混在モードのDLL /アセンブリでリンクするとうまくいかないことです。

// ClrAboutToLoad.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 

#include <MSCorEE.h> 

// http://community.bartdesmet.net/blogs/bart/archive/2005/07/22/2882.aspx 
FLockClrVersionCallback begin_init, end_init; 
STDAPI hostCallback() 
{ 
    printf("hostCallback()\n"); 

    // we're in control; notify the shim to grant us the exclusive initialization right 
    begin_init(); 

    ICLRRuntimeHost *pHost = NULL; 
    HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", STARTUP_SERVER_GC, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*) &pHost); 
    hr = pHost->Start(); 

    // mission completed; tell the shim we're ready 
    end_init(); 

    return S_OK; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    LockClrVersion(&hostCallback, &begin_init, &end_init); 

    //fnTheDLL(); 
    HMODULE hModule = LoadLibrary(L"TheDLL"); 
    FARPROC fp = GetProcAddress(hModule, "fnTheDLL"); 
    typedef void (*fnTheDLL_t)(); 
    fnTheDLL_t fnTheDLL = reinterpret_cast<fnTheDLL_t>(fp); 
    fnTheDLL(); 
    FreeLibrary(hModule); 

    return 0; 
} 

答えて

6

管理対象APIを使用する前に、プロセスがアンマネージドLockClrVersion関数を呼び出すようにすることで、これを行うことができます。この関数では、2つのメソッドを指定できます。

最初のメソッド(pBeginHostSetup)は、ホスティングプロセスで初めてCLRが初期化される前に呼び出されます。 2番目の方法(pEndHostSetup)は、CLRの初期化が完了すると呼び出されます。

これにより、CLR初期化の直前および直後に実行されるアンマネージコードを指定できます。あなたの場合は、おそらくpEndHostSetupに接続して、管理されたAPI設定ルーチンを呼び出す必要があります(CLRが正常にホストされるまで待つ必要があります)。

+0

これは有望そうです! –

+0

これはあなたが何をしているのか正確にする必要があります。私は今まで実装していませんでしたが、CLRホスティングAPI全体を追跡して追跡しました。 –

+0

これはほぼ完璧です。唯一のヒッチは、* LockClrVersion *を呼び出す前に何もCLRがロードされないことを確認する必要があることです。 "問題"は、混合モードアセンブリでリンクするとCLRが読み込まれるため、アセンブリを動的にロードする必要があります。 –

-1

おそらく、アプリケーションの起動時に.NETフレームワークを初期化する必要があります。私は似たバックグラウンドでアプリを開発しました.2つのDLLが.net dllに間接的にアクセスすることで、同じ時間に.netフレームワークを初期化しようとしていたために時折デッドロックになりました。これを修正するために、実行可能ファイルのエントリポイントの最初の数行にCorBindToRuntimeExを呼び出しました。

.NETをロードしようとしている場合、OSから通知される方法はありません。

+0

私からの議論はありません。バイトカウンタには.NETを初期化するためのポイントがありません。これは(非常に)大きなプロジェクトであることを覚えておいてください。作業する技術的な問題だけでなく、政治的な問題もあります。 –

1

run your own CLR host to load assembliesです。次に、ロードするランタイムのバージョン(1.1?2.0?4.0?)をより具体的に判断し、コードからマネージコードを分離することができます。when a plugin crash, your code won't go down with it

+0

私はそれについて考えました...しかし、バイトカウンターは正確に.NETを取り入れていません。 COM相互運用機能のおかげで、.NETが存在するにもかかわらず、(ほとんど)幸せに気付かずに済むことができます(.NETで書かれた「新しい機能」はそれらに強制されました)。 –

1

パフォーマンスカウンターとWMIの2つが役立ちます。 .NET CLRは両方とも統合されているため、AppDomainの起動を監視するには、どちらかと対話できる必要があります(おそらくWMIが最適です)。しかし、これらのツールは特に理想的ではありません。また、オーバーヘッドの観点から、Sheng Jiangが提案したCLRを自分でホストすることで、より効率的になります(したがって、 "バイトカウンター"がより快適になります)。

若干異なる注記...開発チームに対する影響力とコントロールの尺度があれば、私は「バイトカウンター」で少し治めるでしょう。 .NETに関する最大の誤解の1つは、C++より効率が低いことです。 .NETは驚くほど効率的であり、正しく使用されるときにはC++より効率的であるため、古い誤解を埋める必要があります。どちらのプラットフォームのベースライン効率を超えても、統計的には通常は性能を低下させる大規模なものがあると、未知数の時間を無駄に費やすことによって実際にどれだけ効率が上がりますか? (つまり、C++からCOMオブジェクトを呼び出して.NETの.NETオブジェクトを呼び出す)、リモートプロセス(Webサービス、RPCなど)を呼び出す、データベースに呼び出す、などを呼び出します。

.NET AppDomainの起動時に問題が発生して、バイトカウンタの誤解を緩和したり、.NETシステムを適切に実装したり、バイトレベルのパフォーマンスチューニングに比べて大量に流出するマーシャリングや相互運用のヒットを回避できます。

+0

私からの議論はありません。しかし、古い誤解は大変です。 –

+0

Heh、あまりにも真実。悲しい、しかし間違いなく真実。 – jrista

0

アセンブリがロードされたときにフックしようとするのではなく、AppDomainがロードされたときにフックできますか?これを行うには、System.AppDomainManagerを調べます。

サブクラス化されたSystem.AppDomainManagerをGACにロードした後、C++プログラムを実行する前にいくつかの環境変数(APPDOMAIN_MANAGER_TYPE、APPDOMAIN_MANAGER_ASM)を設定するだけで済みます。

+0

.NET(CLR)がロードされようとしているとき、アセンブリまたはAppDomainではなくいつロードするかを知りたい。つまり、アンマネージ(OK、混在)プロセスがマネージコードを初めて実行する準備ができていることを知りたいと思います。 –

関連する問題