Search code examples
c++mfchwndcdialogcwnd

Simplest way to read MFC messages from HWND?


I am trying to use an api library with functions that send messages to a server, then receive back messages. One of the function's arguments is a HWND and the library document says the message will be received by it. To read the received message I studied a few MFC documents, created a class that inherits CDialog with a function to handle the message and tried to work with the message map.

But these efforts seemed like a bit too much trouble when I don't want to create a working dialog window, but just want the message itself so I can make it appear in a console or use it in other parts of my code. So is there any way to simply 'extract' the message from HWND and not worry about MFC? If not, what is the simplest way?


More on the API doc

Class Wrapper wraps the dll library file into member functions, I'm trying to use the function BOOL Wrapper::Func1(HWND hWnd, DWORD msg, const char* inputStr)

Class MyDlg inherits CDialog and has Wrapper m_wrp as its class member.

LRESULT MyDlg::HandleEvent(WPARAM w, LPARAM l) is a member function that prints the recieved data and returns TRUE

There's this code in the middle of the cpp file where member functions of MyDlg are defined. It seems that whatever inputStr is sent to the server by Wrapper::Func1, the same message CA_01 is received. CA_01 is a const DWORD defined in another header file. After some searching I believe this is the part that continuously checks for messages and if MSG with msg = CA_01 is received, calls HandleEvent.:

BEGIN_MESSAGE_MAP(MyDlg, CDialog)
    ON_MESSAGE(CA_01, HandleEvent)
END_MESSAGE_MAP()

There is a button MyDlg creates, and when it is pressed, input text is read, void MyDlg::OnSend() is called and m_wrp.Func1(...) is called.

void MyDlg::OnSend(){
    CString strData;
    m_editData.GetWindowText(strData);
    m_wrp.Func1(GetSafeHwnd(), CA_01, strData);
}

I have tested this sample code from the api document, and it works fine. A window with a editable text box and a button appears, I enter some text, press the button, and after a few seconds the received message is shown.

However, when I create a Wrapper instance, and inside a while loop, try to call Func1 and recieve the message using PeekMessage, nothing happens:

HWND hWnd = CreateWindowW(L"static", L"", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
MSG msg;
Wrapper m_wrp;
CString inputStr = "test";

while (true){
    m_wrp.Func1(hWnd, CA_01, inputStr);
    if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) {
        std::cout << "Got message: " << msg.message << std::endl;
    }
    else {
        std::cout << "No messages, sleep" << std::endl;
        Sleep(2000);
    }
}

Is this because of a difference between ON_MESSAGE(...) and PeekMessage(...)?


Solution

  • You sure don't need MFC for that. Not even a "Windows" app - a simple console app will work, just keep pumping messages:

    #include <iostream>
    #include <windows.h>
    
    int main() {
        HWND hWnd = CreateWindowW(L"static", L"", 0,
            0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
    
        MSG msg;
        while (true) {
            if(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) {
                std::cout << "Got message: " << msg.message << std::endl;
            }
            else {
                std::cout << "No messages, posting '7' and sleep" << std::endl;
                PostMessage(hWnd, 7, 0, 0);
                Sleep(2'000);
            }
        }
    }
    

    UPDATE:

    The code above works only for posted messages. To also process sent messages, this minimal sample will work:

    #include <iostream>
    #include <windows.h>
    
    const DWORD CA_01 = WM_USER + 1;
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if (message == CA_01)
            std::cout << "Got message: " << message << std::endl;
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    ATOM MyRegisterClass()
    {
        WNDCLASSEXW wcex{ sizeof(WNDCLASSEX) };
        wcex.lpfnWndProc = WndProc;
        wcex.hInstance = ::GetModuleHandle(NULL);
        wcex.lpszClassName = L"x";
        return RegisterClassExW(&wcex);
    }
    
    int main() {
        HWND hWnd = CreateWindowW((LPCWSTR)MyRegisterClass(), L"", 0,
            0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
    
        std::cout << "Sending `CA_01`" << std::endl;
        LRESULT lr = SendMessageW(hWnd, CA_01, 0, 0);
        MSG msg;
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            DispatchMessage(&msg);
        }
    }
    

    May be that library on your app to pump windows messages? Try to add a in instead of the while loop (see modified code above)