Search code examples
c#wpfwinapisendmessagewindows-messages

Wait for message delivered to MainWindow sent using SendMessage API


The application has multiple process,Process communicate through IPC. Main process is written in C# and has Windows form and DefWndProc. Another process sends the message to main process window through SendMessage API,however messages are not getting immediately received in DefWndProc. Is there a way I can wait for the messages in receiving process ?

I have tried sleep and timer in the main window,however message is getting received only after the delay

Process A- WinForm Application,defwndproc is implemented here Process B-Use SendMessage API to send message to Process A Window

My main intention is process the message sent to main window immediately,I can see that Message is not gettting delivered to DefWndProc immediately


Solution

  • Here is the sample code in C++,(Removed error checking)

    MainWindow.cpp:

    #include <windows.h>
    #include <iostream>
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    DWORD WINAPI createyourwindow(LPVOID param)
    {
        WNDCLASSEXW wcex = { 0 };
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        HWND* hWnd = (HWND*)param;
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc = WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = GetModuleHandle(NULL);
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wcex.lpszClassName = L"MyClass";
        RegisterClassExW(&wcex);
        *hWnd = CreateWindowW(L"MyClass", L"window", WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
    
        if (!*hWnd)
        {
            return FALSE;
        }
    
        ShowWindow(*hWnd, SW_NORMAL);
        UpdateWindow(*hWnd);
        MSG msg;
    
        // Main message loop:
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, NULL, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return 0;
    }
    
    int main()
    {
        DWORD ThreadId;
        HWND hwnd = NULL;
        HANDLE hThread = CreateThread(NULL, 0, createyourwindow, (LPVOID)&hwnd, 0, &ThreadId);
        MSG msg;
        DWORD tid = GetCurrentThreadId(); // used in the PostThreadMessage().
        // Main message loop:
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (msg.message == WM_USER && hwnd != NULL)
            {
                SuspendThread(hThread);
                printf("suspend\n");
    
                getchar(); //To Do here. 
    
                ResumeThread(hThread);
            }
        }
        WaitForSingleObject(hThread, INFINITE);
        return 0;
    
    }
    

    PostThreadMessage.cpp:

    #include <windows.h>
    #include <iostream>
    int main()
    {
        DWORD tid = 0x....;
        PostThreadMessage(tid,WM_USER,0,0);
        return 0;
    }
    

    in MainWindow.cpp, create the main window in a thread and then there is also a messageloop in the main thread just to receive your user message. And then suspend the thread of mainwindow, to do something you want, finally resume it.

    UPDATE:

    WinForm Program.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Threading;
    using System.Runtime.InteropServices;
    namespace WindowsFormsApp2
    {
        static class Program
        {
            static uint WM_USER = 0x0400;
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
    
            static void Main()
            {
                Thread thread = new Thread(MainWindow);
                thread.Start();
                MSG msg = new MSG();
                uint tid = GetCurrentThreadId();
                while (GetMessage(ref msg, IntPtr.Zero, 0, 0) == 1)
                {
                    if (msg.message == WM_USER)
                    {
                        //Thread.Sleep(5000);  //You could still move the window for 5 second(just for test)
                        thread.Suspend();
    
                        Thread.Sleep(5000);  //To Do here. 
    
                        thread.Resume();
                    }
                }
            }
            static void MainWindow()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            [DllImport("user32.dll")]
            private static extern int GetMessage(ref MSG msg, IntPtr hwnd, uint wMsgFilterMin, uint wMsgFilterMax);
            [DllImport("Kernel32.dll")]
            private static extern uint GetCurrentThreadId();
            private struct MSG
            {
                public IntPtr hwnd;
                public uint message;
                public uint wParam;
                public long lParam;
                public ulong time;
                public long x;
                public long y;
            }
        }
    }
    

    Then postmessage to the tid.