首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PeekMessage总是返回FALSE

PeekMessage总是返回FALSE
EN

Stack Overflow用户
提问于 2022-07-26 13:03:19
回答 2查看 142关注 0票数 0

我编写了一个小型测试应用程序,通过延迟呈现将文件(带有硬编码的路径)插入到当前活动的文件夹/应用程序中。它如预期的那样工作。但是我有一个问题--为什么PeekMessage总是返回FALSE?但是,如果删除PeekMessage调用,则永远不会调用Wndproc。我读了一个类似的帖子,但是我在同一个线程中创建了一个窗口,在这个线程中我试图处理消息。

代码:

代码语言:javascript
复制
static LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
    switch (Msg) {      
        case WM_RENDERALLFORMATS: {
            OpenClipboard(hWnd);
            EmptyClipboard(); 
        }
        case WM_RENDERFORMAT: {
            printf("WM_RENDERFORMAT received");
            
            <Here the file paths are copied to the clipboard>

            if (Msg == WM_RENDERALLFORMATS)
                CloseClipboard();
            return 0;
        }
        case WM_DESTROYCLIPBOARD:
            return 0;
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

HWND hwnd_;

void thread_(void* ignored) {
    WNDCLASSEX wcx = { 0 };
    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.lpfnWndProc = WindProc;
    wcx.hInstance = GetModuleHandle(NULL);
    wcx.lpszClassName = TEXT("my_class");
    RegisterClassEx(&wcx);

    hwnd_ = CreateWindowEx(0, TEXT("my_class"), TEXT(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);

    MSG msg;
    while (true) {
        if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
            printf("PeekMessage returned TRUE\n");
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            break;
        }
        Sleep(1000);
    }
}

void main() {
    CloseHandle((HANDLE)_beginthread(thread_, 0, NULL));

    // let's give some time to thread to create msg window
    Sleep(100);

    if (OpenClipboard(hwnd_)) {
        EmptyClipboard();
        SetClipboardData(CF_HDROP, NULL);
        CloseClipboard();
    }

    while (true) {
        Sleep(100);
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-26 15:43:42

PeekMessage() (和GetMessage())只返回通过PostMessage()PostThreadMessage()发送到调用线程的消息队列的消息。当调用时没有已发布的消息可用时,PeekMessage()返回FALSE。GetMessage()会阻塞,直到发布的消息可用为止。

但是,所讨论的消息(WM_RENDERFORMATWM_RENDERALLFORMATS)将通过SendMessage...()直接发送到目标窗口。但是,这些消息是由另一个线程发送的,因此仍然需要PeekMessage() (或GetMessage()),因为它们内部分派跨线程边界发送的消息。

这在[经]文件中有说明。

发布传入的非队列消息,检查线程消息队列中的已发布消息,并检索消息(如果存在的话)。 ..。 在此调用期间,系统分发(**DispatchMessage**)挂起的、非排队的消息,即使用 SendMessage**,** SendMessageCallback**,** SendMessageTimeout**,或** SendNotifyMessage 函数将消息发送到调用线程拥有的窗口。然后检索与指定筛选器匹配的第一个排队消息。系统还可以处理内部事件。如果未指定筛选器,则按以下顺序处理邮件:

  • 发送消息
  • 张贴的信息
  • 输入(硬件)消息和系统内部事件
  • 再次发送消息(再次)
  • WM_PAINT消息
  • WM_TIMER消息

以及文档

从调用线程的消息队列中检索消息。函数发送传入的发送消息,直到发布的消息可供检索。 ..。 在此调用期间,系统传递挂起的、非排队的消息,即使用SendMessage**,** SendMessageCallback**,** SendMessageTimeout**,或** SendNotifyMessage 函数将消息发送到调用线程拥有的窗口。然后检索与指定筛选器匹配的第一个排队消息。系统还可以处理内部事件。如果未指定筛选器,则按以下顺序处理邮件:

  • 发送消息
  • 张贴的信息
  • 输入(硬件)消息和系统内部事件
  • 再次发送消息(再次)
  • WM_PAINT消息
  • WM_TIMER消息

[经]文件

如果指定的窗口是由调用线程创建的,则将立即作为子例程调用窗口过程。如果指定的窗口是由不同的线程创建的,则系统切换到该线程并调用适当的窗口过程。只有当接收线程执行消息检索代码时,才会处理在线程之间发送的消息。发送线程被阻塞,直到接收线程处理该消息。但是,发送线程将在等待其消息被处理时处理传入的非队列消息。要防止这种情况,请将SendMessageTimeoutSMTO_BLOCK集一起使用。有关非排队邮件的详细信息,请参阅非排队消息

尽管如此,您对WM_RENDERALLFORMATS消息的处理是错误的。一方面,它不能调用EmptyClipboard(),另一方面,在呈现其数据之前,它不检查您的应用程序是否仍然是剪贴板所有者。有关这些要点为何重要,请参见雷德尔福玛斯?

此外,您的主线程中有一个竞赛条件。在调用OpenClipboard()之前,它只休眠100 is,等待首先创建窗口,但不能保证在这100 is内分配了hwnd_。例如,只需要花那么长的时间才能使工作线程开始运行。

更好的选择是,在创建窗口时让辅助线程向事件发出信号,然后让主线程等待该事件(更好的方法是在创建窗口后将初始的SetClipboardData()调用移动到辅助线程本身,但您已经排除了该选项)。

尝试更像这样的东西:

代码语言:javascript
复制
static LRESULT CALLBACK WindProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {      

        /*
        case WM_CREATE:
            if (OpenClipboard(hWnd)) {
                EmptyClipboard();
                SetClipboardData(CF_HDROP, NULL);
                CloseClipboard();
            }
            return 0;
        }
        */

        case WM_RENDERALLFORMATS: {
            if (OpenClipboard(hWnd)) {
                if (GetClipboardOwner() == hWnd) {
                    SendMessage(hWnd, WM_RENDERFORMAT, CF_HDROP, 0);
                }
                CloseClipboard();
            }
            return 0;
        }

        case WM_RENDERFORMAT: {
            printf("WM_RENDERFORMAT received");            
            if (wParam == CF_HDROP) {
                // <Here the file paths are copied to the clipboard>
            }
            return 0;
        }

        case WM_DESTROYCLIPBOARD:
            return 0;
    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

HWND hwnd_ = NULL;

void thread_(void* arg) {
    HANDLE hEvent = (HANDLE)arg;

    WNDCLASSEX wcx = { 0 };
    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.lpfnWndProc = WindProc;
    wcx.hInstance = GetModuleHandle(NULL);
    wcx.lpszClassName = TEXT("my_class");
    RegisterClassEx(&wcx);

    hwnd_ = CreateWindowEx(0, TEXT("my_class"), TEXT(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);

    SetEvent(hEvent);

    if (hwnd_ == NULL) {
        return 0;
    }

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        printf("GetMessage returned a message\n");
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

int main() {
    HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!hEvent)
        return 1;

    uintptr_t res = _beginthread(thread_, 0, hEvent);
    if (res == -1L) {
        CloseHandle(hEvent);
        return 1;
    }

    WaitForSingleObject(hEvent, INFINITE);
    CloseHandle(hEvent);

    if (hwnd_ != NULL) {
        if (OpenClipboard(hwnd_)) {
            EmptyClipboard();
            SetClipboardData(CF_HDROP, NULL);
            CloseClipboard();
        }
    }

    HANDLE hThread = (HANDLE)res;
    WaitForSingleObject(hThread, INIFINTE);
    CloseHandle(hThread);

    return 0;
}
票数 2
EN

Stack Overflow用户

发布于 2022-07-26 15:18:18

为什么PeekMessage总是返回FALSE

假设传递给PeekMessage的窗口句柄是有效的,那么PeekMessage返回FALSE的原因只是队列中没有消息。

文档可以看出情况是这样的,它说:

如果消息可用,则返回值为非零。 如果没有可用的消息,则返回值为零。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73123875

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档