【问题标题】:How can I get a message from another process when I don't have a window handle?当我没有窗口句柄时,如何从另一个进程获取消息?
【发布时间】:2012-09-11 05:53:29
【问题描述】:

我有 2 个程序,我需要一种方法让其中一个程序以某种方式向另一个程序发送消息。我研究了 Win32 API 中的 SendMessage 函数,虽然只要你有一个窗口句柄,它就可以很好地工作,但我的程序需要能够在服务下注销时运行,这意味着它不能创建窗口句柄.

有什么方法可以在不创建窗口句柄的情况下接收来自另一个进程的消息?我一直在寻找Win32是否有其他方式可以连接到消息传递中,这样我就不需要依赖窗口句柄,但是必须有某种方式在基本级别的进程之间进行通信,不是吗不在那里?

我已经研究过使用 Pipe 来执行此操作,但遇到了巨大的权限问题,而且它的级别比我真正想要的要高得多。我需要做的就是发送一个简单的自定义 int 消息,以便我的进程知道是时候关闭了。

【问题讨论】:

  • 我有发布愚蠢回复的危险,但是,您是否考虑过将共享内存用于 IPC?似乎很适合您的应用程序(请参阅msdn.microsoft.com/en-us/library/windows/desktop/…)。邮槽也可能很适合 (msdn.microsoft.com/en-us/library/windows/desktop/…)。希望这可以帮助!让我知道您的应用程序是否有某些东西使所有这些方法变得无关紧要。
  • 我会和@Ivan 一起做这个。这可能很简单,例如设置注册表值或文件中的值,然后让服务监视或轮询它。 Naff 但又快又简单。
  • 命名管道是要走的路。我现在遇到了他们的权限问题,任何其他机制都不会变得更好。
  • 其他答案和 cmets 已经解释了更好的方法来做到这一点,但要澄清的是,服务可以创建窗口,它们只是不能与桌面或任何其他会话交互。
  • @HansPassant SendMessage 在与管道完全相同的情况下根本没有给我们任何权限问题,所以我知道有些方法没有那么多限制。我对管道导致这些问题的最佳猜测是因为它们可以发送更复杂的消息

标签: c winapi inter-process-communicat


【解决方案1】:

如果您的 IPC 不需要任何参数,您的服务可以实现其 Handler/Ex() 查找的自定义控制代码,然后其他应用可以使用 ControlService() 将该控制代码发送到服务。

不过,可以使用ControlService(SERVICE_CONTROL_STOP) 代替以编程方式关闭服务。该服务应在其Handler/Ex() 收到SERVICE_CONTROL_STOP 请求时自行关闭。

【讨论】:

    【解决方案2】:

    这很好用:

    // msg.c:
    
    #include <windows.h>
    #include <stdio.h>
    
    int CALLBACK WinMain (_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
        MSG msg;
        DWORD curThreadId;
    
        curThreadId = GetCurrentThreadId();
    
        // Send messages to self:
        PostThreadMessage(curThreadId, WM_USER, 1, 2);
        PostThreadMessage(curThreadId, WM_USER+1, 3, 4);
        PostThreadMessage(curThreadId, WM_USER+2, 5, 6);
        PostThreadMessage(curThreadId, WM_USER+3, 7, 8);
        PostThreadMessage(curThreadId, WM_QUIT, 9, 10);
    
        while (GetMessage(&msg, NULL, 0, 0)) {
            printf("message: %d; wParam: %d; lParam: %d\n", msg.message, msg.wParam, msg.lParam);
        }
    
        return (int) msg.wParam;
    }
    

    制作:

    > g++ -m64 -mwindows -c -o msg.o msg.c
    > g++ -s -o msg.exe msg.o
    > msg.exe
    message: 1024; wParam: 1; lParam: 2
    message: 1025; wParam: 3; lParam: 4
    message: 1026; wParam: 5; lParam: 6
    message: 1027; wParam: 7; lParam: 8
    
    > echo %ERRORLEVEL%
    9
    

    【讨论】:

      【解决方案3】:

      如果真的像通知其他程序关闭一样简单,那么您可以create a named event。两个进程都创建具有相同名称的事件。一个监视它,另一个可以发出信号。观看者可以通过修改后的消息泵来做到这一点,该消息泵使用MsgWaitForMultipleObjects 而不是 PeekMessage。

      这里存在轻微的拒绝服务风险,因为恶意进程可能会创建同名事件并导致您的其他应用程序退出。

      如果您需要更复杂的通信,则需要管道、邮槽、共享内存、文件监视、注册表监视或使用其他可同步的内核事件(Mutex、Semaphore 等)。

      【讨论】:

      • 消息泵?只需要一个三行线程 - 创建命名事件,使用 WaitForSingleObject 等待它,调用 ExitProcess(0)。
      • @Martin James:我认为重点是以有序的方式关闭进程,在这种情况下,您可能必须将通知发送到 UI 线程。如果您只是想终止该进程,您也可以从其他程序中终止该进程。此外,这个问题暗示他/她通常会使用 Window 消息来执行此操作,所以我认为意图是在消息泵中接收通知。
      • 我看错了。我以为服务正在向交互进程发送信号。
      • @MartinJames 你是正确的,除了 ExitProcess 调用:)。这样做的目的是避免不得不终止进程,而是让它干净地退出。不过,这可以通过我可以从线程中翻转的 bool 轻松完成,因此这个解决方案看起来非常有前途。
      • 这很棒!非常感谢您向我指出这些功能!我所做的唯一不同是改用 WaitForSingleObject,但这只是因为它更符合我的需要。
      猜你喜欢
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多