13

管理されたプラグインをロードできるプラグイン システムを作成しようとしています。例外があれば、ホストはプラグインをアンロードできるはずです。私の poc には、このような例外をスローする C# のサンプル コード ライブラリがあります ...

 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) を削除すると、ホスト プロセスがクラッシュします。 .

管理されていないホストで、エラーのあるアプリをランタイムから適切に削除して作業を続行できるようにすることはできますか?

4

4 に答える 4

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 つ (Polyity によって提案されていると思います) は、すべての未処理の例外を簡単にキャッチできる中間の AppDomain を作成することです。次のように、C# でそれを行うことができます。

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 から派生する必要があります
  • プラグイン メソッドは静的であってはなりません (静的メソッドの呼び出しは 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);        

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

于 2011-11-04T14:20:36.203 に答える
1

SetDefaultActionと一緒に以下を追加すると、クラッシュが解決するようです。

clrPolicyManager->SetUnhandledExceptionPolicy(EClrUnhandledException::eHostDeterminedPolicy);
于 2011-10-30T16:46:07.787 に答える
1

特定のプラグインごとに新しい AppDomain を開始し、内部で起動できます。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

于 2011-11-03T10:26:02.013 に答える
0

あなたは非常に興味深い質問を提起しました、ありがとう。

この記事は十分に役立つと思います: http://etutorials.org/Programming/programming+microsoft+visual+c+sharp+2005/Part+III+More+C+Language/Chapter+9+Exception+Handling/Unhandled +例外/

于 2011-11-04T10:30:01.793 に答える