Visual Studio 2012调试远程进程无法按预期工作

Tim*_*ter 12 c# debugging windows-services remote-debugging visual-studio-2012

我正在努力应对一个相当困难的调试挑战,并希望有人可能有一些线索如何使这项工作.

这是场景:

我有一个C#Windows服务,在具有管理员权限的用户帐户下运行,并在具有标准用户权限的用户帐户下启动单独的可执行进程.这两个进程旨在使用WCF进行通信.

不幸的是,当子进程启动时,它立即崩溃,事件日志中没有任何内容表明发生了什么.父进程继续运行,没有例外.

有关信息:这两个应用程序在父进程是桌面应用程序的配置中可靠地协同工作.我已经成功将父作为Windows服务,但只有当两个进程在具有管理员权限的同一用户帐户下运行时才能成功.

我现在需要重新配置它们的关系以限制子进程的权限,但这是发生崩溃的时候.

为了证明我尝试做的是可行的,我创建了两个存根应用程序并在所需的配置中成功启动它们.因此,我可以推断出我的真实子应用程序包含的内容与此配置不兼容,甚至在代码开始执行之前就会导致崩溃.遗憾的是,由于子进程是基于一些相当复杂的遗留代码,因此在消除问题之前隔离其元素并不容易,所以我真的需要一种可靠的方法来逐步完成它.

如果我修改子进程的代码以在启动时立即启动调试,它会邀请我附加调试器,但无法完成附件,并显示一条消息The Just-in-time debugger does not have permission to debug the process.

我也看到了这个问题并试图实现这个提议的解决方案(看起来很有希望),但它在我的场景中无法工作.它不是在启动应用程序之前启动调试,而是似乎什么都不做 - 无论调试器还是应用程序都启动,并且不显示调试邀请对话框.但是,我已经验证了这种技术在我的环境中工作(通过使用它来启动Notepad.exe),因此显然有一些关于我的应用程序或我正在启动它的方式导致问题.

如果有人有任何建议,我很乐意尝试并分享有关我的测试结果的更多详细信息.

非常感谢你的想法,

蒂姆

Roa*_*ior 2

根据我基于上述场景的测试(父进程是具有管理员权限的服务,子进程是没有管理员权限的控制台),当我人为地强制子进程一旦抛出权限异常时,我会看到与您相同的调试错误开始。此实例中的错误消息可能会产生误导,因为尚不清楚这实际上是调试器权限问题

了解您的子进程是什么类型的应用程序会很有用,因为这会影响您拥有的调试选项。

我尝试调试此问题的第一种方法是拦截子进程(控制台应用程序)中的所有未处理的异常。您可以通过在子应用程序的启动过程中添加以下代码来完成此操作:

AppDomain.CurrentDomain.UnhandledException += new 
    UnhandledExceptionEventHandler(App_UnhandledException);
Run Code Online (Sandbox Code Playgroud)

然后,我将代码添加到App_UnhandledException过程中以记录异常。这对我有用,我可以看到权限错误的原因。唯一需要注意的是,这不会拦截您的应用程序因权限问题而无法加载的异常。但这种方法至少应该减少您在理解权限问题方面的搜索空间。

如果异常是在到达异常处理程序之前生成的,则另一种可能性是使用程序集绑定日志查看器。这是一个非常有用的工具。

FWIW,您可以通过在 Visual Studio 中启动服务来逐步执行您的服务代码(但遗憾的是不能进入您的子进程)。下面在名为 DEBUG 的 switch case 中显示的代码将允许您在 VS 中启动/调试服务。

// This is the entry point
static void Main(string[] args)
{
    // If parameter passed, act on it
    if ( args.Length > 0 )
    {
        switch (args[0] )
        {
            // Debug the service as a normal app from within Visual Studio
            case DEBUG:
                MyService DebugService = new MyService();
                DebugService.OnStart(null);
                break;
            // Install the service programatically
            case INSTALL:
                ManagedInstallerClass.InstallHelper(new string[] _
                { Assembly.GetExecutingAssembly().Location });
                break;
            // Un-install the service programatically
            case UNINSTALL:
                ManagedInstallerClass.InstallHelper(new string[] +
                { UNINSTALL, Assembly.GetExecutingAssembly().Location });
                break;
            // We don't understand this parameter!
            default:
                message = string.Concat(DEBUG, " to run service manually.",     Environment.NewLine);
                message += string.Concat(INSTALL, " to install service.",     Environment.NewLine);
                message += string.Concat(UNINSTALL, " to un-install service.",     Environment.NewLine);
                message += string.Concat("Do not understand the command-line parameter ", args[0]);
                throw new System.NotImplementedException(message);
        }
    }
    // If no parameter passed, just start the service normally
    else
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new MyService() };
        ServiceBase.Run(ServicesToRun);
    }
}
Run Code Online (Sandbox Code Playgroud)