我有一个Windows服务,用于监控连接到供应商硬件的COM端口。这是一个非常繁忙的硬件,它不断轮询线路上的其他设备(这是一个双绞线RS485“网络”)。我的软件需要在这条线路上模拟X个硬件设备,所以我有一个多线程的东西,用多层状态机来跟踪通信协议的位置。
问题在于Windows服务(这是我的第一个,BTW)是你需要一些调试来让你知道东西是否正常工作。当我第一次开发这个状态机/多线程代码时,我有一个带有RichTextBox的Windows窗体,它显示了在行上向后移动的ASCII字符。好像我不能真正拥有服务的GUI友好。我尝试通过另一个程序在服务中打开一个表单,该程序发送通过OnCustomCommand()处理程序接收的服务消息,但它似乎不起作用。我检查了“允许服务与桌面交互”和所有内容。我正在使用调试表单的Show()和Hide()方法。
我想我不需要看到所有单个角色都在线,但是那个肯定会很好的人(我想我真的需要看到它们:-))。那么有没有人有任何可以帮助我的疯狂想法?我不想让系统陷入困境,因为某些IPC并不适合那些肯定会通过的大量数据。它只是非常短期的调试,只是确认程序,RS485到USB加密狗和硬件都在工作。
答案 0 :(得分:4)
使用OutputDebugString写入调试缓冲区,然后使用DebugView进行观察。如果您在Windows XP或更早版本上运行,则可以使用PortMon查看通过串行端口的原始字节。与日志文件相比,优势在于开销非常小,特别是在您不看时。您甚至可以从另一台计算机运行DebugView并远程监控您的服务。
答案 1 :(得分:2)
我不知道它是否适合你,但我总是使用额外的Main构建我的服务,将它们构建为控制台应用程序以获得调试输出。
编辑:
一些例子:
class Worker : ServiceBase
{
#if(RELEASE)
/// <summary>
/// The Main Thread where the Service is Run.
/// </summary>
static void Main()
{
ServiceBase.Run(new Worker());
}
#endif
#if(DEBUG)
public static void Main(String[] args)
{
Worker worker = new Worker();
worker.OnStart(null);
Console.ReadLine();
worker.OnStop();
}
#endif
// Other Service code
}
答案 2 :(得分:1)
您可以将输出写入日志文件,然后使用其他应用程序来查看该文件。关于"tail"的这个问题概述了使用Windows观看日志文件的几个选项。
答案 3 :(得分:0)
在Windows服务上工作时我通常会创建它,以便它既可以作为服务运行,也可以作为普通的旧命令行应用程序运行。您可以通过检查Environment.UserInteractive来轻松检查您是否作为服务运行。如果此属性为true,则表示您正在从命令行运行。如果属性为false,则表示您正在作为服务运行。将此代码添加到Program.cs,并在通常调用ServiceBase.Run(servicesToRun)的地方使用它
/// <summary>Runs the provided service classes.</summary>
/// <param name="servicesToRun">The service classes to run.</param>
/// <param name="args">The command-line arguments to pass to the service classes.</param>
private static void RunServices(IEnumerable<ServiceBase> servicesToRun, IEnumerable args)
{
var serviceBaseType = typeof(ServiceBase);
var onStartMethod = serviceBaseType.GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStartMethod.Invoke(service, new object[] { args });
Console.WriteLine(service.ServiceName + " started.");
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
var onStopMethod = serviceBaseType.GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStopMethod.Invoke(service, null);
Console.WriteLine(service.ServiceName + " stopped.");
}
}
现在您可以调试服务,设置断点,任何您想要的东西。当您运行应用程序时,您将获得一个适合显示控制台消息的控制台窗口,它将保持打开状态,直到您按下某个键。
答案 4 :(得分:0)
我在这里回答我自己的问题。我在这里尝试了一些建议,但这就是我最终做的......
我使用单个Button和RichTextBox创建了一个Windows窗体应用程序。这个应用程序在它的末尾构造了一个NamedPipeServerStream。 Button的工作是将“debug on”(命令128)或“debug off”(129)发送到Windows服务。初始值为“debug off”。单击该按钮时,会向Windows服务发送128命令以打开调试。在Windows服务中,这触发了一个内部变量为true,加上它与NamedPipeClientStream连接到Form应用程序,并开始发送带有BinaryWriter的字符,因为它们是在COM端口上接收或发送的。在表单端,为管道上的WaitForConnection()创建了BackgroundWorker。当它连接时,使用BinaryReader.ReadString()从管道读取数据并将其射向RichTextBox。
我快到了。当我再次单击调试按钮并且后续单击未正确重做管道时,我正在断开管道。总而言之,我很高兴。如果有人有兴趣,我可以发布任何代码。感谢您的回复!