2011-10-25 23 views
12

管理プラグインをロードできるプラグインシステムを作成しようとしています。例外がある場合、ホストはプラグインをアンロードできなければなりません。 私のPOCの私はこのような例外をスローC#でのサンプルコードライブラリを持っている...clrのホスティングとスレッド例外のキャッチ

public static int StartUp(string arguments) 
{ 
     Console.WriteLine("Started exception thrower with args {0}", arguments); 
     Thread workerThread = new Thread(() => 
      { 
       Console.WriteLine("Starting a thread, doing some important work"); 
       Thread.Sleep(1000); 
       throw new ApplicationException(); 
      } 
     ); 
     workerThread.Start(); 
     workerThread.Join(); 
     Console.WriteLine("this should never print"); 
     return 11; 
    } 

その後、私はこのようなネイティブのWin32コンソールアプリケーションを持っている...

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ICLRMetaHost *pMetaHost  = NULL; 
    HRESULT hr; 
    ICLRRuntimeInfo *runtimeInfo = NULL;  
    __try 
    { 
     hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 
     hr = pMetaHost->GetRuntime(L"v4.0.30319",IID_ICLRRuntimeInfo,(LPVOID*)&runtimeInfo); 
     ICLRRuntimeHost *runtimeHost = NULL; 
     hr = runtimeInfo->GetInterface(CLSID_CLRRuntimeHost,IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);  
     ICLRControl* clrControl = NULL; 
     hr = runtimeHost->GetCLRControl(&clrControl); 
     ICLRPolicyManager *clrPolicyManager = NULL; 
     clrControl->GetCLRManager(IID_ICLRPolicyManager, (LPVOID*)&clrPolicyManager); 
     clrPolicyManager->SetDefaultAction(OPR_ThreadAbort,eUnloadAppDomain); 
     hr = runtimeHost->Start(); 
     DWORD returnVal = NULL;   
     hr = runtimeHost->ExecuteInDefaultAppDomain(L"ExceptionThrower.dll",L"ExceptionThrower.MainExceptionThrower",L"StartUp",L"test",&returnVal);   
     runtimeHost->Release(); 
    } 
    __except(1) 
    { 
     wprintf(L"\n Error thrown %d",e); 
    } 
    return 0; 
} 

問題があればということです上記のコードを使用すると、ホストはマネージコードの実行を完了します( "これは決して印刷しないでください"という行が印刷されます) clrPolicyManager-> SetUnhandledExceptionPolicy(eHostDeterminedPolicy)を削除すると、ホストプロセスがクラッシュします。

管理対象外のホストでは、実行時に間違ったアプリを正常に削除して作業を続けることができますか?

+0

コードで.NET 1.xの例外処理ポリシーが有効になっています。これは単にスレッドを終了させます。あなたが望むものではなく、ICLRPolicyManager :: SetDefaultAction()を呼び出して、スレッドがアボートしたときにアプリドメインをアンロードするように指示する必要があります。あなたはまだどこかにデッドスレッドがありますが、例外をキャッチするには__try/__ catchを使用します。 –

+0

次の行を追加しました。clrPolicyManager-> SetDefaultAction(OPR_ThreadAbort、eUnloadAppDomain);コードに私はコードを更新しましたが、効果は同じですが、ホストプロセスはまだクラッシュします –

+0

あなたはコメントの「デッドスレッド」の部分を見逃しているかもしれません。 SEH例外を捕捉する必要があります。例外コードは0xe0434f4dです。 http://msdn.microsoft.com/en-us/library/s58ftw19%28v=VS.100%29.aspx –

答えて

1

あなたは、与えられた各プラグインのために特別に新しいアプリケーションドメインを開始し、内部にそれを起動することができます。 http://msdn.microsoft.com/en-us/library/ms164323.aspx

各AppDomainは、コードを実行できる独立した環境です。 1つのAppDomainで発生した例外は残りの部分から隔離することができます。参照:http://msdn.microsoft.com/en-us/library/system.appdomain(v=VS.100).aspx

+0

ドメインはメモリ/セキュリティサンドボックスを提供しますが、スレッドの分離を提供しません。つまり、スレッドはCLRレベルで作成され、どのドメインでも実行できるため、スレッドで未処理の例外が発生した場合、CLR全体がクラッシュします。 。 –

+0

@ np-hard - 「アプリケーションドメインを使用してプロセスを停止させる可能性のあるタスクを分離する」タスクを実行しているAppDomainの状態が不安定になると、AppDomainはプロセスに影響を与えることなくアンロードできます。プロセスを再起動せずに長期間実行する必要がある場合アプリケーションドメインを使用してデータを共有しないタスクを分離することもできます。 (http://msdn.microsoft.com/en-us/library/system.appdomain.aspx) – Polity

+0

@ np-hard - http://ikickandibite.blogspot.com/2010/04/appdomains-and-を参照してください。 true-isolation.htmlはあなたの問題を正確に扱います。 CLR-Hosting APIを使用してこれを複製できるかどうかはわかりません。もしそうでなければ、手直しされていない例外を正常に処理するplugin-dllの管理されたブートストラップを開発することができます – Polity

1

はSetDefaultActionと一緒に以下をクラッシュを解決する追加のようになります。

clrPolicyManager->SetUnhandledExceptionPolicy(EClrUnhandledException::eHostDeterminedPolicy); 
+0

「問題は、私が上記のコードを使用すると、ホストが(これは決して印刷されないはずの行は印刷されるはずです。)clrPolicyManager-> SetUnhandledExceptionPolicy(eHostDeterminPolicy)を削除すると、ホストプロセスがクラッシュします。 –

0

非常に興味深い質問をいただきました。ありがとうございました。

私はこの記事が十分に参考になると仮定します。すべてのhttp://etutorials.org/Programming/programming+microsoft+visual+c+sharp+2005/Part+III+More+C+Language/Chapter+9+Exception+Handling/Unhandled+Exceptions/

+3

ネイキッドリンクは良い回答にはなりません。 **こちらの記事は**まとめてください。リンクされたコンテンツが動いた場合、この答えは役に立たないよりも悪くなります。また、あなたのすべての答えに署名する必要はありません、彼らはあなたの印であるあなたの感覚を添付しています。 – ChrisF

3

まず、あなたは上記のコードを使用してアプリケーションのクラッシュを防ぐためにしたい場合、あなたはこのように、SetUnhandledExceptionFilterを使用する必要があります:

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo) 
{ 
    // do something useful 
    return EXCEPTION_EXECUTE_HANDLER; // prevent crash 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); 
     ... 
} 

これはあなたが本当に望むものではないかもしれません。 1つの解決策(Polityが提案したように)は、すべての未処理の例外を簡単にキャッチできる中間AppDomainを作成することです。これが動作できるようにするには

public class PluginVerifier 
{ 
    public static int CheckPlugin(string arguments) 
    { 
     AppDomain appDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString()); 
     appDomain.UnhandledException += AppDomainUnhandledException; 
     object obj = appDomain.CreateInstanceAndUnwrap("ExceptionThrower", "ExceptionThrower.MainExceptionThrower"); 
     object ret = obj.GetType().InvokeMember("Startup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, obj, new object[] { arguments }); 
     AppDomain.Unload(appDomain); 
     return (int)ret; 
    } 

    private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     AppDomain appDomain = (AppDomain)sender; 
     // the following will prevent "this should never print" to happen 
     AppDomain.Unload(appDomain); 
    } 
} 

しかし、あなたはプラグインクラスに2つの変更を行う必要があります:

  • 彼らはMarshalByRefObjectを
  • から派生しなければなりませんあなたは、C#で、このようにそれを行うことができますプラグインメソッドが静的であってはなりません
  • (静的メソッドは、AppDomainのフィルターを通過しない呼び出す)

だからあなたのクラスは次のように書かれます:

public class MainExceptionThrower: MarshalByRefObject 
{ 
    public int StartUp(string arguments) 
    { 
    ... 
    } 
} 

あなたがこれを行う場合、あなたはSetUnhandledExceptionPolicy、SetActionOnFailure、またはSetDefaultActionへの呼び出しを削除し、ちょうどこのようなブートストラップコードを置き換えることができます。

hr = runtimeHost->ExecuteInDefaultAppDomain(L"PluginSystem.dll", L"PluginSystem.PluginVerifier", L"CheckPlugin", L"test", &returnVal);   

あなたは上記のスタートアップコードでこれをしようとすると、この呼び出しはhr = 0x80131604を返します。これはCOR_E_TARGETINVOCATION(TargetInvocationException)です。