是否可以在不在 C++ 中创建 window 的情况下创建消息循环
Is it possible to create a message loop without creating a window in C++
我正在使用一些蓝牙库和一些蓝牙回调,有必要使用 Windows 消息循环。但根据我的要求,我需要创建一个没有任何 GUI 的普通 C++ 程序。是否可以在没有 window 的情况下创建消息循环?
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 将消息队列与线程相关联when/if 该线程尝试使用一个线程。不过,这样做时会出现一些竞争条件。要post到线程的消息队列,你使用PostThreadMessage
。但是,线程在调用函数尝试从消息队列中读取之前不会有消息队列(即,Windows 在线程尝试使用它之前不会为线程创建消息队列) .
为防止竞争条件,您通常需要按以下顺序执行某些操作:
- 调用 CreateEvent 以创建事件(未发出信号)
- 调用
CreateThread
,将要传递给新线程的事件句柄传递给它
- 让parent等待事件
- 让 child 调用
PeekMessage
(不期待任何结果,因为队列尚未创建——但这会强制创建它)。
- 让 child 发出事件信号
- 现在 parent 将恢复,并且可以使用
PostThreadMessage
,在 "knowledge" 中安全,child 有一个消息队列,所以这会起作用。
另一种可能性是 child 创建一个 window,但将其隐藏。这里的明显优势是与期望使用 SendMessage
、PostMessage
、SendMessageTimeout
等将 post/send 消息发送到普通消息队列的代码兼容,而不是特殊的 PostThreadMessage
。另一个明显的优点是它避免了上面概述的 thread-message-queue 舞蹈。
当你认真对待它时,Windows "window" 的主要特征不是显示在屏幕上的东西——它是一个消息队列,显示在屏幕上的只是为响应某些特定消息而完成的绘图。隐藏的 window 并不比消息队列多多少。
非 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;
}
我正在使用一些蓝牙库和一些蓝牙回调,有必要使用 Windows 消息循环。但根据我的要求,我需要创建一个没有任何 GUI 的普通 C++ 程序。是否可以在没有 window 的情况下创建消息循环?
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 将消息队列与线程相关联when/if 该线程尝试使用一个线程。不过,这样做时会出现一些竞争条件。要post到线程的消息队列,你使用PostThreadMessage
。但是,线程在调用函数尝试从消息队列中读取之前不会有消息队列(即,Windows 在线程尝试使用它之前不会为线程创建消息队列) .
为防止竞争条件,您通常需要按以下顺序执行某些操作:
- 调用 CreateEvent 以创建事件(未发出信号)
- 调用
CreateThread
,将要传递给新线程的事件句柄传递给它 - 让parent等待事件
- 让 child 调用
PeekMessage
(不期待任何结果,因为队列尚未创建——但这会强制创建它)。 - 让 child 发出事件信号
- 现在 parent 将恢复,并且可以使用
PostThreadMessage
,在 "knowledge" 中安全,child 有一个消息队列,所以这会起作用。
另一种可能性是 child 创建一个 window,但将其隐藏。这里的明显优势是与期望使用 SendMessage
、PostMessage
、SendMessageTimeout
等将 post/send 消息发送到普通消息队列的代码兼容,而不是特殊的 PostThreadMessage
。另一个明显的优点是它避免了上面概述的 thread-message-queue 舞蹈。
当你认真对待它时,Windows "window" 的主要特征不是显示在屏幕上的东西——它是一个消息队列,显示在屏幕上的只是为响应某些特定消息而完成的绘图。隐藏的 window 并不比消息队列多多少。
非 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;
}