Arm*_*yan 47 c# c++ debugging windows-services
我阅读了有关该主题的MSDN文章.报价:
由于服务必须在服务控制管理器的上下文中而不是在Visual Studio中运行,因此调试服务并不像调试其他Visual Studio应用程序类型那样简单.要调试服务,必须启动该服务,然后将调试器附加到运行它的进程.然后,您可以使用Visual Studio的所有标准调试功能来调试应用程序.
现在我的问题是我的服务首先无法启动.首先它崩溃,并说:
MyServiceName.exe [3596]中发生未处理的异常(System.Runtime.InteropServices.COMException)
并建议我调试它(当我选择一个时,调试器实例会立即崩溃).然后它说
无法在本地计算机上启动MyServiceName服务.错误1053:服务未及时响应启动或控制请求
那么,我如何调查/调试我的服务无法启动的原因?问题是我创建了一个控制台应用程序,它完全可以完成服务的工作,并且工作正常.(我的意思是我只是将OnStart
()方法和主循环的内容复制到main中.
任何帮助,将不胜感激.
该服务是用C#编写的,大量使用互操作.我正在使用VS2008
Bro*_*ass 38
您可以使用参数让您的应用程序决定是作为服务还是常规应用程序启动(即在本例中显示表单或启动服务):
static void Main(string[] args)
{
if ((1 == args.Length) && ("-runAsApp" == args[0]))
{
Application.Run(new application_form());
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您传递参数"-runAsApp",您可以正常调试应用程序 - SCM不会传递此参数,因此您也可以将其用作任何代码更改的服务(前提是您派生的ServiceBase
)
编辑:
与Windows服务的另一个区别是身份(这可能对InterOp尤其重要) - 您希望确保在"app"模式和服务模式下以相同的身份进行测试.
为此,您可以在应用程序模式下使用模拟(我可以发布C#包装器,如果它有帮助,但这可以很容易地用Google搜索),以使用您的Windows服务将运行的相同标识,即通常是LocalService或NetworkService.
如果需要其他身份,您可以向app.config添加设置,以便您决定是否使用凭据,如果是,则使用哪个用户进行模拟 - 这些设置在作为应用程序运行时处于活动状态,但是对于Windows服务已关闭(因为服务已经在所需的身份下运行):
<appSettings>
<add key="useCredentials" value="false"/>
<add key="user" value="Foo"/>
<add key="password" value="Bar"/>
</appSettings>
Run Code Online (Sandbox Code Playgroud)
Dav*_*ido 21
我通常只是手动设置断点,然后将其指向c#中当前打开的项目.设置断点的代码是:
System.Diagnostics.Debugger.Break();
Run Code Online (Sandbox Code Playgroud)
这应该让你开始,然后你可以单步执行代码,看看到底发生了什么.
Kei*_*thS 14
我从C. Lawrence Wenham那里偷了这个,所以我不能真正理解,但你可以通过以下代码以编程方式将调试器附加到服务,而不会在此时断开执行:
System.Diagnostics.Debugger.Launch();
Run Code Online (Sandbox Code Playgroud)
将它放在服务的OnStart()方法中,作为第一行,它将提示您选择VS的实例来附加其调试器.从那里,系统将在您设置的断点处停止,并在抛出异常时停止.我会#if DEBUG
在代码周围添加一个子句,因此Release版本不会包含它; 或者你可以在发现问题后将其剥离.
您可以使用WinDbg/NTSD("Windows调试工具"包中的另一个调试器)与您的服务一起启动调试器.
要执行此操作,请在"图像文件"选项卡中打开"gflags"(也可在上述包中找到),并为图像文件(服务)设置调试程序可执行文件的路径;
如果您的服务被标记为交互式(只有在SYSTEM帐户下运行),您可以直接启动WinDbg,只需将调试器设置为"PATH_TO_WINDBG\windbg.exe -g -G"(-g/-G是需要使调试器不会破坏应用程序开始或结束时的执行 - 默认行为).现在,在启动服务时,应该弹出windbg窗口并捕获任何未处理的异常.
如果您的服务不是交互式的,您可以在远程模式下启动NTSD调试器(命令行调试器)并从WinDbg连接到它(甚至可以在另一台PC上运行).为此,请将gflags中的调试器设置为"PATH_TO_NTSD \ntsd -remote tcp:port = 6666,server = localhost".然后通过启动windbg连接到远程调试器,例如"windbg -remote tcp:port = 6666,server = localhost",你应该完全控制其他调试会话.
至于查找异常的来源本身,windbg教程已经超出了这个主题,但作为一个开始尝试在捕获到异常后执行"!analyze -v"命令 - 幸运的是,这是您需要的所有信息. .
注意:也许这对你的情况来说太过分了,但是通过这种方法你甚至可以在系统启动期间调试服务(我曾经有一个服务的计时问题只有在第一次启动系统时出现问题)
我做的一件事(可能是一种黑客行为)Thread.Sleep(10000)
在我的OnStart()
方法开头就是正确的.这给了我一个10秒的窗口,可以在我做任何其他事情之前将我的调试器连接到服务.
当然,Thread.Sleep()
当我完成调试时,我删除了该语句.
您可能做的另一件事是:
public override void OnStart()
{
try
{
// all your OnStart() logic here
}
catch(Exception ex)
{
// Log ex.Message
if (!EventLog.SourceExists("MyApplication"))
EventLog.CreateEventSource("MyApplication", "Application");
EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
记录时ex.Message
,您可能会收到更详细的错误消息.此外,您可以只记录ex.ToString()
以获取整个堆栈跟踪,如果您的.pdb文件与可执行文件位于同一目录中,它甚至会告诉您异常发生在哪一行.
似乎问题在于用户上下文.让我确认一下我的假设是否正确.
当您说代码从控制台应用程序完美运行时,我假设您正在您登录的同一用户下执行控制台应用程序.
当您说从Windows服务调用时相同的代码崩溃时,我认为该服务正在您的开发机器中的"本地系统"帐户中运行.
如果我的假设都是正确的,请尝试以下步骤.
在服务列表中,右键单击您的服务,选择属性,然后选择"登录"选项卡.
选择"此帐户"选项并提供现有用户名和密码.
现在尝试启动该服务.它应该现在开始没有任何错误.
以下可能是您的错误的根本原因
如果您使用的是SQL Server,请确保未使用SSPI身份验证.
如果您尝试读取使用"本地系统"帐户时没有权限的任何共享文件夹\资源.
如果应用程序所需的任何所需依赖项位于"本地系统"用户无权访问的其他文件夹中.
如果您使用的VBA自动化不能在"本地系统"帐户中使用.
尝试禁用防火墙或防病毒软件.
归档时间: |
|
查看次数: |
24925 次 |
最近记录: |