【问题标题】:Send windows message to a Windows Service向 Windows 服务发送 Windows 消息
【发布时间】:2009-08-05 13:15:44
【问题描述】:

是否有任何工具可以向 Windows 服务发送(模拟)诸如“WM_ENDSESSION”之类的 Windows 消息?

如何使用 C# 向进程发送 Windows 消息?

(我只知道 C#)

编辑:目的:基本上我必须调试一个 Windows 服务来修复仅在系统关闭时出现的错误。

【问题讨论】:

  • 我认为它属于 stackoverflow.com

标签: c# .net winapi windows-services shutdown


【解决方案1】:

应使用ServiceController class控制服务

表示 Windows 服务,并允许您连接到正在运行或已停止的服务、操作它或获取有关它的信息。

您可以使用它来启动、停止并与使用此类的服务进行通信。

【讨论】:

    【解决方案2】:

    通常,服务没有窗口(更不用说消息泵)来接收窗口消息。

    如果错误确实只在关闭时发生(而不是仅仅停止服务),则可能是某些事情依赖于正在消失的资源,而该资源没有得到妥善处理(在这种情况下,错误修复可能是正确设置服务依赖项)。您是否尝试过在关闭前使用远程调试工具附加到进程?

    如果您可以在不关闭的情况下发生问题,则值得调查,也许只是在使用服务控制管理器停止服务时(无需以编程方式执行此操作,因为这是一个调试方案),在这种情况下,您可以在您的服务中断点 OnStop()(我假设是 C#)并观察会发生什么。

    【讨论】:

    • 我感觉依赖项对关机没有帮助...但我不确定。
    【解决方案3】:

    查看How to simulate windows shutdown while debugging?的答案

    服务有一个他们可以订阅的名为 OnShutdown 的“事件”,因此问题可能出在该代码中。如果代码是 .net,您可以对其进行子类化,以便调用受保护的 OnShutdown 方法进行调试。但问题也可能是其他人所建议的那样,该服务期望资源可用,而不是因为它们已经关闭。

    另外,如果服务是用 .net 2.0 编写的,请注意,当工作站关闭时,服务不会自动调用 Stop() 命令!这是非常令人惊讶的,是 fixed in .net 3.5,但如果您使用的是 .net 2.0,您需要在 OnShutdown() 中自己调用 Stop()。

    【讨论】:

      【解决方案4】:

      如果你有一个窗口的 hwnd,你可以给它发送消息。唯一的限制是您不能发送包含诸如设置窗口文本之类的指针的消息。
      只需使用 hwnd 的值和您要发送的消息调用 PostMessage()
      要找到 hwnd,您可以使用 spy++。

      我不确定你是如何将所有这些连接到 Windows 服务的,因为 Windows 服务没有 Windows。

      【讨论】:

        【解决方案5】:

        我建议导入并定义以下内容:

        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
        public static extern bool PostMessage(IntPtr handleWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
        
        const int WM_ENDSESSION = 0x0016,
                  WM_TRUE = 0x1,
                  WM_FALSE = 0x0;
        

        然后通过代表真假的0x1或0x0作为wParam消息发送。

        所以在你的代码中你将使用:

        PostMessage(HandleToSendTo, WM_ENDSESSION, WM_TRUE, 0);
        

        HandleToSendTo 是您要将消息发送到的窗口的窗口句柄。

        编辑
        如果您不知道 Windows 句柄,我假设您会知道它的标题或名称。如果是这样,您可以使用它:

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
                public static extern int FindWindowEx(int hwndParent, int hwndEnfant, int lpClasse, string lpTitre);
        

        更多信息可以在this question.找到

        或许

        我不知道这是否是一个类似的句柄,我对此表示怀疑,但有人可以让我知道是否是,但你可以获得一个 Process 句柄,这意味着你可以使用 Process.GetProcessesByName(" MyAppName");,虽然不要依赖这个,因为我认为它不会得到你所追求的句柄。只是一个建议。

        【讨论】:

          【解决方案6】:

          我认为没有发送任意消息的工具,因为每条消息都可以具有任意 LPARAM 和 WPARAM 值。

          但是围绕 Windows 消息最有用的工具是 spy++。 Spy++ 包含在 Visual Studio 中,它可以帮助您查看发送的消息、窗口层次结构等。

          您可以使用 SendMessage Win32 API 通过 C# 发送消息。您可以使用 Win32 API(如 FindWindowFindWindowEx)获取它要求的窗口句柄。

          编辑(以匹配问题的编辑):服务在关机时由 Windows 自动停止。因此,要修复您的错误,听起来您需要修改服务本身的代码才能正确关闭。

          Edit2:或者如果你想停止服务,你应该使用 Win32 API ControlService 传入 SERVICE_CONTROL_STOP 0x00000001

          【讨论】:

          • 但我必须向作为 Windows 服务运行的进程发送消息? FindWindow 在这种情况下如何工作?
          • 服务必须首先有一个窗口或消息队列才能向它发送消息。并且根据 Vista 设置,您可能无法将消息发送到在不同会话中运行的服务。如果您可以控制服务,则更好的选择是管道。
          【解决方案7】:

          我不知道这是否是一个类似的句柄,我对此表示怀疑,但有人可以让我知道是否是,但你可以获得一个 Process 句柄,这意味着你可以使用 Process.GetProcessesByName(" MyAppName");,虽然不要依赖这个,因为我认为它不会得到你所追求的句柄。只是一个建议。

          实际上这个方法可以工作...你只需要访问进程对象的'MainWindowHandle'属性。比如……

          Process myProcess;
          Int handle;
          myProcess = Process.GetProcessesByName("MyAppName");
          handle = myProcess.MainWindowHandle;
          

          【讨论】:

            猜你喜欢
            • 2021-12-05
            • 2011-05-22
            • 1970-01-01
            • 2016-04-27
            • 1970-01-01
            • 1970-01-01
            • 2012-07-03
            • 1970-01-01
            • 2010-12-02
            相关资源
            最近更新 更多