2013-03-15 86 views
5

我的C#代码使用模拟由通过P调用Win32函数/调用为什么来自模拟代码的异常未被捕获?

internal class Win32Native 
{ 
    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern int ImpersonateLoggedOnUser(IntPtr token); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern int RevertToSelf(); 
} 

try { 
    var token = obtainTokenFromLogonUser(); 
    Win32Native.ImpersonateLoggedOnUser(token); 
    throw new Exception(); // this is for simulation 
    Win32Native.RevertToSelf() 
} catch(Exception e) { 
    LogException(e); 
    throw; 
} 

还我AppDomain.CurrentDomain.UnhandledException处理程序安装还记录所有未处理的异常。

我敢肯定,记录异常的代码在使用和不使用模拟时都可以正常工作。

现在的问题是,在上面的代码中,它看起来像没有输入catchUnhandledException也没有被调用。事件查看器中的条目是唯一的异常跟踪。

如果我添加一个finally这样的:

try { 
    var token = obtainTokenFromLogonUser(); 
    Win32Native.ImpersonateLoggedOnUser(token); 
    try { 
     throw new Exception(); // this is for simulation 
    } finally { 
     Win32Native.RevertToSelf() 
    } 
} catch(Exception e) { 
    LogException(e); 
    throw; 
} 

则异常无论从catchUnhandledException处理记录好。

发生了什么事?被模拟的线程是否阻止了常规的异常处理?

+0

如果你在'LogException'上放置一个断点:你到那里了吗? – 2013-03-15 10:02:18

+0

@MarcGravell:我不知道,没有调试器在哪里复制。我意识到'LogException()'本身可能存在一些问题,但到目前为止,它所依赖的代码都可以正常工作,并且不会被模拟。 – sharptooth 2013-03-15 10:04:12

+0

在这里做一个猜测:因为.NET会跟踪执行上下文,所以异常处理可能会意识到上下文已经改变,并且正在阻止异常处理程序执行,除非首先执行回复。如果代码与模拟用户一起运行,则不这样做会导致特权提升...... – 2013-03-15 12:26:11

回答

3

没有看到LogException的代码,我不能确定,但​​它可能是,无论你在那里做的是在模拟/登录用户的情况下这样做,并且该用户没有用户无论你在做什么都有权利做例如写入一个文件等,然后代码崩溃在那一刻。事实上,你的代码只有在你“恢复自我”之后才能起作用,这似乎证明了这一点。

所以我想说的是,你的异常实际上是被catch捕获的,但是由于它试图在不正确的用户上下文中工作,LogException失败了。

要测试这一点,在LogException中,尝试在尝试任何日志记录之前强制当前上下文为“Self”,并查看第一个片段是否现在开始工作。

1

原来问题出在日志代码上。在某些时候,我们添加了检索当前进程开始时间(Process.StartTime)的代码,并且从模拟线程调用该代码时产生Access denied

Access is denied 
System.ComponentModel.Win32Exception 
at System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) 
at System.Diagnostics.Process.GetProcessTimes() 
at System.Diagnostics.Process.get_StartTime() 
//our logging code here 

记录代码也叫System.Diagnostics.Trace.WriteLine()之前Process.StartTime调用代码,并通过“跟踪侦听器”成功地写道,只写通过后者的代码失败。

因此,在有或没有假冒的情况下捕捉例外情况没有区别。甚至可以安装一个异常过滤器,以便在可能导致权限提升的模拟代码的安全上下文中调用它。 Details for the latter here