旧学校Win32仅消息窗口无法接收消息

时间:2018-02-13 03:45:09

标签: c++ winapi sendmessage

我意识到控制台win32应用程序没有干净利落,所以我尝试切换到仅限消息的窗口。我正在从另一个进程启动应用程序并尝试彻底杀死它。

这是win32应用程序,它在启动时生成一个calc.exe,在干净关闭时,它应该杀死calc.exe

LRESULT CALLBACK    WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_USER:   PostQuitMessage (0); break;
    default: return DefWindowProc (hWnd, message, wParam, lParam);break;
    }
    return 0;
}

int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int show)
{
    WNDCLASSEX wc = { 0 };
    wc.cbSize        = sizeof (WNDCLASSEX);
    wc.lpfnWndProc   = WindowProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = L"WindowClass1";

    RegisterClassEx (&wc);

    HWND hWnd = CreateWindowEx (NULL,
                L"WindowClass1",    // name of the window class
                L"Our First Windowed Program",   // title of the window
                0,
                //WS_OVERLAPPEDWINDOW,    // window style
                300,300,500,400,
                HWND_MESSAGE,
                //NULL,    // parent window, NULL
                NULL, hInstance, NULL);

    //ShowWindow (hWnd, SW_HIDE);

    PROCESS_INFORMATION pi;
    CreateWindowProcess (L"calc.exe", pi); // helper class to createprocess

    MSG msg = { 0 };
    while (true)
    {
        if (PeekMessage (&msg, 0, 0, 0, PM_REMOVE))
        {
            if (WM_QUIT == msg.message)
                break;
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
    }

    // terminate the spawn process, this is not called cleanly
    TerminateProcess (pi.hProcess, 0);
    return (int)msg.wParam;
}

我创建了一个c#程序,通过发送WM_QUIT / WM_CLOSE / WM_USER消息来干净地启动/终止应用程序(calc.exe被破坏)。除非窗口可见(WS_OVERLAPPED和ShowWindow为true),否则Win32应用程序不会收到消息。收到PostMessage WM_QUIT但是calc.exe没有被销毁,这意味着它不是一个干净的退出。

我应该如何从C#app中彻底杀死它?

    class Program
    {
        [DllImport ("user32.dll")]
        public static extern bool    PostMessage (IntPtr hwnd, uint msg, int wparam, int lparam);

        [DllImport ("User32.dll")]
        public static extern int     SendMessage (IntPtr hWnd, uint uMsg, int wParam, int lParam);

        static void                                                             Main (string [] args)
        {
            try
            {
                Process myProcess;
                myProcess = Process.Start ("My.exe");

                // Display physical memory usage 5 times at intervals of 2 seconds.
                for (int i = 0; i < 3; i++)
                {
                    if (myProcess.HasExited) break;
                    else
                    {
                        // Discard cached information about the process.
                        myProcess.Refresh ();
                        Thread.Sleep (4000);

                        Console.WriteLine ("Sending Message");

                        const int WM_USER = 0x0400;
                        const int WM_CLOSE = 0xF060;      // Command code for close window
                        const int WM_QUIT = 0x0012;

                        // Received only when windows is visible
                        //int result = SendMessage (myProcess.MainWindowHandle, WM_USER, 0, 0);

                        // not clean exit
                        PostMessage (myProcess.MainWindowHandle, WM_QUIT, 0, 0);
                        // doesn't receive
                        SendMessage (myProcess.MainWindowHandle, WM_QUIT, 0, 0);
                    }
                }
            }
    }
}

1 个答案:

答案 0 :(得分:1)

Windows上的进程实际上没有“MainWindow”。 Process.MainWindowHandle是C#进行猜测,它通过查看相关进程是否有一个焦点窗口来猜测 - 这只会找到可见的窗口。使用WM_DESTROY查找要关闭的窗口句柄。

接下来,当窗口关闭时,它不会自动尝试退出当前线程消息循环。您需要处理PostQuitMessage来致电GetMessage

在您的消息循环中使用PeekMessage而不是PeekMessage如果您没有进行任何其他工作,因为如果没有消息意味着应用程序线程永远不会有机会,WM_CLOSE会立即返回睡觉。

通过这些更改,您可以将WM-QUIT简单地发布到有效窗口句柄,因为它将被销毁,发布$("#P15").find("#C").css({fill: "#333333"}); 消息以退出消息循环,并终止计算过程正确。