将Windows消息发送到Windows服务

时间:2009-08-05 13:15:45

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

是否有任何工具可以向Windows服务发送(模仿)像'WM_ENDSESSION'这样的Windows消息?

OR

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

(我只知道C#)

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

7 个答案:

答案 0 :(得分:10)

应使用ServiceController class

控制服务

您可以使用它来启动,停止和与服务进行通信。

答案 1 :(得分:4)

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

如果错误确实只发生在关机上(而不是仅仅停止服务),那么可能是某些东西取决于一个正在消失的资源,而这个资源没有得到优雅处理(在这种情况下,错误修复可能是正确设置服务依赖关系)。您是否尝试使用远程调试工具在关闭之前附加到进程?

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

答案 2 :(得分: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()。

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

[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发送表示true或false的wParam消息。

因此,在您的代码中,您将使用:

PostMessage(HandleToSendTo, WM_ENDSESSION, WM_TRUE, 0);

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

修改
如果您不知道窗口处理,我假设您将知道它的标题或名称。如果是这样,你可以使用它:

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

有关详细信息,请参阅this question.

或者

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

答案 5 :(得分:0)

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

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

您可以使用SendMessage Win32 API通过C#发送消息。您可以使用FindWindowFindWindowEx等Win32 API来获取要求的窗口处理。

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

Edit2:或者,如果您要停止该服务,则应使用传入SERVICE_CONTROL_STOP 0x00000001的Win32 API ControlService

答案 6 :(得分:0)

  

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

实际上这个方法会起作用......你只需要访问过程对象的'MainWindowHandle'属性。对于实例......

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