簡體   English   中英

是否可以在 C++ 中不創建窗口的情況下創建消息循環

[英]Is it possible to create a message loop without creating a window in C++

我正在使用一些藍牙庫,對於一些藍牙回調,有必要使用 Windows 消息循環。 但是根據我的要求,我需要創建一個沒有任何 GUI 的普通 C++ 程序。 是否可以在沒有窗口的情況下創建消息循環?

main(){
    Discovery disc;
    disc.startDiscovery();
}


Discovery::startDiscovery(){
  __hook(&CallBackFromLibrary::OnDiscoveryStarted, &obj, &Discovery::OnDiscoveryStarted);
  __hook(&CallBackFromLibrary::OnDiscoveryComplete, &obj, &Discovery::OnDiscoveryComplete);  
}


apiObject.discoverBluetoothDevices();

在此示例代碼中,我應該在調用 apiObject.discoverBluetoothDevices() 后接收作為 OnDiscoveryStarted 和 OnDiscoveryComplete 的回調。

由於他們使用消息循環進行回調,因此我只在 GUI 應用程序上獲得了回調。 如何使用消息循環接收回調,因為庫文檔說需要消息循環。

是的,這是可能的——當/如果線程嘗試使用一個線程時,Windows 會將一個消息隊列與一個線程相關聯。 不過,這樣做時會有一點競爭條件。 要發布到線程的消息隊列,請使用PostThreadMessage 但是,線程在調用函數嘗試從消息隊列中讀取之前不會有消息隊列(即,在線程嘗試使用消息隊列之前,Windows 不會為該線程創建消息隊列)。

為了防止競爭條件,您通常希望按以下順序執行某些操作:

  1. cal CreateEvent 創建一個事件(無信號)
  2. 調用CreateThread ,將要傳遞給新線程的事件句柄傳遞給它
  3. 讓父母等待事件
  4. 讓孩子調用PeekMessage (不期望任何結果,因為尚未創建隊列 - 但這會強制其創建)。
  5. 讓孩子發出事件信號
  6. 現在父級將恢復,並且可以使用PostThreadMessage ,確保子級具有消息隊列的“知識”安全,因此這將起作用。

另一種可能性是讓孩子創建一個窗口,但將其隱藏。 這里的明顯優勢是與期望使用SendMessagePostMessageSendMessageTimeout將消息發布/發送到普通消息隊列的代碼兼容,而不是特殊的PostThreadMessage 另一個明顯的優點是它避免了上面概述的線程消息隊列舞蹈。

當您深入了解它時,Windows“窗口”的主要特征不是顯示器上的某些東西——它是一個消息隊列,顯示器上顯示的只是響應某些特定消息而完成的繪圖。 隱藏窗口只不過是一個消息隊列。

非 GUI 線程中的消息循環:

#include "stdafx.h"
#include <Windows.h>
#include <thread>
#include <iostream>
using namespace std;

void ThreadFunction()
{
    MSG msg;
    BOOL result;

    for (;;)
    {
        result = GetMessage(&msg, nullptr, 0, 0);

        if (result <= 0)
        {
            break;
        }

        cout << msg.message << " " << msg.wParam << " " << msg.lParam << endl;

        //TranslateMessage(&msg);
        //DispatchMessage(&msg);
    }
}

int main()
{
    thread t(ThreadFunction);
    HANDLE h = t.native_handle();
    DWORD dw = GetThreadId(h);

    PostThreadMessage(dw, WM_APP + 1, 1, 2);
    PostThreadMessage(dw, WM_APP + 2, 10, 20);
    PostThreadMessage(dw, WM_QUIT, 10, 20);

    t.join();
    return 0;
}

更新

根據評論,這段代碼不是在gcc中編譯的。 試圖在 VC++ 中重現這一點,我發現該程序在 x64 中不起作用。 這個更新的解決方案有望解決這兩個問題:

#include "stdafx.h"
#include <Windows.h>
#include <thread>
#include <iostream>
using namespace std;

DWORD threadID{};


void ThreadFunction(HANDLE event_handle)
{
    MSG msg;
    BOOL result;

    threadID = GetCurrentThreadId();
    SetEvent(event_handle);

    for (;;)
    {
        result = GetMessage(&msg, nullptr, 0, 0);

        if (result <= 0)
        {
            break;
        }

        cout << msg.message << " " << msg.wParam << " " << msg.lParam << endl;
    }
}

int main()
{
    HANDLE e = CreateEvent(nullptr, FALSE, FALSE, nullptr);

    thread t(ThreadFunction, e);

    WaitForSingleObject(e, INFINITE);
    CloseHandle(e);


    PostThreadMessage(threadID, WM_APP + 1, 1, 2);
    PostThreadMessage(threadID, WM_APP + 2, 10, 20);
    PostThreadMessage(threadID, WM_QUIT, 10, 20);

    t.join();
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM