-4

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

cc125
  • 13
  • 1
  • 5
  • 1
    The call to `SendMessage` does not return until the message has been processed by the recipient (and the recipient either returns from its window procedure, or calls `ReplyMessage`). You don't have to do anything special to wait for it to be received. – Jonathan Potter Mar 02 '20 at 06:01
  • @JonathanPotter The problem is I want MainWindow to stop other things and take this message on priority,however it does other things and receive message only after finishing other things – cc125 Mar 02 '20 at 06:15
  • 2
    Maybe you need a separate thread (with its own window) that does nothing but respond to your IPC messages. – Jonathan Potter Mar 02 '20 at 06:29
  • @cc125 when *sending* a message across thread/process boundaries via `SendMessage...()`, the message is not delivered to the receiving window until its owning thread performs message retrieval. Even though the thread's *message loop* won't see the message, the *window procedure* will. It is necessary to make sure the window receives messages in the correct order, so the thread controls when messages are processed. If the thread is busy doing something else, a sent message won't be processed until the thread is ready for it. This is clearly documented on MSDN. – Remy Lebeau Mar 02 '20 at 07:48
  • Waiting is very troublesome. Just move the code that is now after the wait to the message handler or event for the message. – Hans Passant Mar 02 '20 at 09:31
  • Is there any API to wait for message? – cc125 Mar 03 '20 at 04:11
  • As Jonathan's comment, you could create a separate thread without any other messages, and use `GetMessage` to wait your message(you could send with [`PostThreadMessage`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postthreadmessagea)), then call [`SuspendThread`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread) (main window thread)and To Do what you want to handle, then call [`ResumeThread`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread) – Drake Wu Mar 04 '20 at 03:21
  • @DrakeWu-MSFT Any sample example for this implementation – cc125 Mar 08 '20 at 06:39

1 Answers1

0

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.

Drake Wu
  • 6,927
  • 1
  • 7
  • 30