【问题标题】:Message queue for two cpp file with windows API带有 Windows API 的两个 cpp 文件的消息队列
【发布时间】:2021-09-12 07:25:16
【问题描述】:

从一个源文件在队列中发送消息并在另一个源文件中获取消息。我阅读了 Microsoft 的文档并尝试如下实现

test2.c - 发布消息 main.c - 获取消息

Testing1:如果我在单个文件中执行相同的代码并收到数据

测试:相同的代码写在两个单独的文件“if (msg.message == WM_YOUR_MESSAGE)”中,这些语句不满足。

test2.h

typedef struct
{
    int SomeData1;
    int SomeData2;
    int SomeDataN;
} MessageData;

/* Unique IDs for Window messages to exchange between the worker and the 
GUI thread. */

#define WM_YOUR_MESSAGE   ( WM_USER + 3 )

void __cdecl ThreadProc(void* aArg);

test2.c

#include <windows.h>
#include <process.h>
#include "malloc.h"
#include <stdio.h>
#include <test2.h>

volatile DWORD ThreadID_GUI;

void __cdecl ThreadProc(void* aArg)
{
    MessageData* data;

    for (;; )
    {
        Sleep(500);

        /* Allocate memory for a new message data structure */
        data = (MessageData*)malloc(sizeof(*data));

        /* Initialize the message data structure with some information to transfer
           to the GUI thread. */
        data->SomeData1 = 1234;
        data->SomeData2 = 4567;
        data->SomeDataN = 7894;

       PostThreadMessage(ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data);
    }
}

main.c

#include <windows.h>
#include <tchar.h>
#include <process.h>
#include "malloc.h"
#include "stdio.h"
#include<test2.h>

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                 _In_opt_ HINSTANCE hPrevInstance,
                 _In_ LPWSTR    lpCmdLine,
                 _In_ int       nCmdShow)
   {
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.

ThreadID_GUI = GetCurrentThreadId();

/* Start some background thread */
_beginthread(ThreadProc, 0, 0);

// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_TESTMESSAGEQUEUE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
    return FALSE;
}

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTMESSAGEQUEUE));

MSG msg;

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
        /* STEP 3: React on the message sent from the foreign thread */
        if (msg.message == WM_YOUR_MESSAGE)
        {
            MessageData* tmp = (MessageData*)msg.lParam;

                if (tmp->SomeData1 == 1234) {
                printf("someData\n");
            }
            /* Free the data structure associated to the message */
            free(tmp);
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
}

return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style          = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc    = WndProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance      = hInstance;
wcex.hIcon          = LoadIcon(hInstance, 
MAKEINTRESOURCE(IDI_CLIENTMQ));
wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_CLIENTMQ);
wcex.lpszClassName  = szWindowClass;
wcex.hIconSm        = LoadIcon(wcex.hInstance, 
MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable

HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, 
nullptr);

if (!hWnd)
{
  return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM 
 lParam)
 {
 switch (message)
 {
case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, 
         About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;
case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code that uses hdc here...
        EndPaint(hWnd, &ps);
    }
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
default:
    return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

 // Message handler for about box.
 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM 
 lParam)
{
 UNREFERENCED_PARAMETER(lParam);
 switch (message)
{
case WM_INITDIALOG:
    return (INT_PTR)TRUE;

case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    {
        EndDialog(hDlg, LOWORD(wParam));
        return (INT_PTR)TRUE;
    }
    break;
}
return (INT_PTR)FALSE;
}

【问题讨论】:

  • 请显示minimal reproducible example的完整代码。
  • 这是我现在在 VIsual Studio 上尝试的完整代码
  • 不,不是。缺少 Test.h 和 test2.cpp。
  • 对不起,我已经更新了代码
  • 这还不完整。我没有看到 windows.h 包含在某处。

标签: c windows visual-studio c++11 winapi


【解决方案1】:

在您的源代码中填写了所有缺失的信息并删除了无用的代码后,您的代码就可以运行了。

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include "test2.h"

HINSTANCE hInst;
LPCWSTR szWindowClass = L"Piu";
LPCWSTR szTitle = L"Title";

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
    lParam)
{
    switch (message)
    {
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
            /*
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd,
                About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
            */
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code that uses hdc here...
        EndPaint(hWnd, &ps);
    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    ZeroMemory(&wcex, sizeof(wcex));

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    /*
    wcex.hIcon = LoadIcon(hInstance,
        MAKEINTRESOURCE(IDI_CLIENTMQ));
    wcex.hIconSm = LoadIcon(wcex.hInstance,
        MAKEINTRESOURCE(IDI_SMALL));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CLIENTMQ);
    */
    wcex.lpszClassName = szWindowClass;

    return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // Store instance handle in our global variable

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance,
        NULL);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    ThreadID_GUI = GetCurrentThreadId();

    /* Start some background thread */
    _beginthread(ThreadProc, 0, 0);

    // Initialize global strings
//    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
//    LoadStringW(hInstance, IDC_TESTMESSAGEQUEUE, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance(hInstance, nCmdShow))
    {
        return FALSE;
    }

//    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTMESSAGEQUEUE));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        /* STEP 3: React on the message sent from the foreign thread */
        if (msg.message == WM_YOUR_MESSAGE)
        {
            MessageData* tmp = (MessageData*)msg.lParam;

            if (tmp->SomeData1 == 1234) {
                printf("someData\n");
            }
            /* Free the data structure associated to the message */
            free(tmp);
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;

}

test2.c:

#include <Windows.h>
#include "test2.h"

volatile DWORD ThreadID_GUI;

void __cdecl ThreadProc(void* aArg)
{
    MessageData* data;

    for (;; )
    {
        Sleep(500);

        /* Allocate memory for a new message data structure */
        data = (MessageData*)malloc(sizeof(*data));

        /* Initialize the message data structure with some information to transfer
           to the GUI thread. */
        data->SomeData1 = 1234;
        data->SomeData2 = 4567;
        data->SomeDataN = 7894;

        PostThreadMessage(ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data);
    }
}

test2.h

typedef struct
{
    int SomeData1;
    int SomeData2;
    int SomeDataN;
} MessageData;

/* Unique IDs for Window messages to exchange between the worker and the
GUI thread. */

#define WM_YOUR_MESSAGE   ( WM_USER + 3 )

void __cdecl ThreadProc(void* aArg);
extern volatile DWORD ThreadID_GUI;

我删除了菜单和图标,所以没有 .rc 文件。

【讨论】:

  • 我还有一个疑问,因为 PostMessage 在不同的线程中,而 GetMessage 在不同的线程中。是否可以做 _beginthread(ThreadProc, 0, 0);在我的情况下,在 PostMessage 所在的文件中是 test2.c。
  • 您可以在任何线程中使用 PostMessage,并且该消息将在执行 GetMessage 的线程(在您的情况下为主线程)的上下文中检索。 PostMessage 是在线程之间传递信息的最佳方式之一,无需临界区、互斥锁或其他花哨的代码来保护共享数据。重要的一点:线程上下文完全独立于代码在多个源中的拆分方式。在多个源中拆分代码由编译器处理,而线程上下文由操作系统在运行时处理。
  • 如何检查消息队列是否已满或消息已发布的确切数量
  • 您可以使用PeekMessage 从队列中获取(有或没有从队列中删除)一条消息(根据您通过的过滤器的顶部消息)或GetMessage 等待消息并阅读它。
猜你喜欢
  • 1970-01-01
  • 2019-04-30
  • 2012-03-16
  • 2012-12-14
  • 2018-06-30
  • 2018-07-18
  • 2019-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多