很多朋友都会有过这样的经历,为什么在主线程中创建窗口且窗口工作很正常,但一移到非主线程(有的朋友喜欢叫它为工作线程),却无法正常工作.本文就这个问题和各位探讨,可能无法做到尽善尽美,但能抛砖引玉也算是欣慰了.
   
   在主线程中创建一个能够正常工作的窗口,估计地球人都知道.
   
   这是一段工作正常的代码:

#include "windows.h"HWND g_hWnd = NULL;
HINSTANCE g_hInst;LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{return DefWindowProc(hWnd,wMsg,wParam,lParam);
}void CreateWnd(void)
{    WNDCLASS wc = {0};wc.style         = 0;wc.lpfnWndProc   = WndProc;wc.cbClsExtra    = 0;wc.cbWndExtra    = 0;wc.hInstance     = g_hInst;wc.hIcon         = NULL; wc.hCursor       = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);wc.lpszMenuName  = NULL;wc.lpszClassName = TEXT("SimpleWindow");RegisterClass(&wc);g_hWnd = CreateWindowEx(0,TEXT("SimpleWindow"),TEXT("SimpleWindow"),WS_VISIBLE,0,0,200,200,NULL, NULL, g_hInst, 0);
}int WINAPI WinMain(    HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR    lpCmdLine,int       nCmdShow)
{// TODO: Place code here.
    g_hInst = hInstance;CreateWnd();//The message loop
    MSG msg;while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

如果我们创建一个线程,然后在这个线程中创建窗口,看看带给我们的是什么:

#include "windows.h"HWND g_hWnd = NULL;
HINSTANCE g_hInst;LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{return DefWindowProc(hWnd,wMsg,wParam,lParam);
}void CreateWnd(void)
{    WNDCLASS wc = {0};wc.style         = 0;wc.lpfnWndProc   = WndProc;wc.cbClsExtra    = 0;wc.cbWndExtra    = 0;wc.hInstance     = g_hInst;wc.hIcon         = NULL; wc.hCursor       = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);wc.lpszMenuName  = NULL;wc.lpszClassName = TEXT("SimpleWindow");RegisterClass(&wc);g_hWnd = CreateWindowEx(0,TEXT("SimpleWindow"),TEXT("SimpleWindow"),WS_VISIBLE,0,0,200,200,NULL, NULL, g_hInst, 0);
}DWORD CreateThread(PVOID pArg)
{CreateWnd();return 0;
}int WINAPI WinMain(    HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR    lpCmdLine,int       nCmdShow)
{// TODO: Place code here.
    g_hInst = hInstance;HANDLE hThrd = CreateThread(NULL,0,CreateThread,NULL,0,NULL);CloseHandle(hThrd);//The message loop
    MSG msg;while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

我们似乎什么都没见到,只是窗口一闪,啥都没了.因为g_hWnd为全局变量,我们的理智告诉我们,在主线程没有退出之前,g_hWnd是不会销毁的.而用断点调试,将会发现在WndProc函数中只能接收WM_CREATE及以后一些消息,之后的再也收不到了,特别是WM_PAINT似乎就凭空消失了!那么,代码什么都没变更,只是移动到了分线程中,为何会出现这个问题呢?
    
    一切似乎很简单,在MSDN中我们找到了答案(原文见:http://support.microsoft.com/kb/90975/en-us):
    
    In a multithreaded application, any thread can call the CreateWindow() API to create a window. There are no restrictions on which thread(s) can create windows.

It is important to note that the message loop and window procedure for the window must be in the thread that created the window. If a different thread creates the window, the window won't get messages from DispatchMessage(), but will get messages from other sources. Therefore, the window will appear but won't show activation or repaint, cannot be moved, won't receive mouse messages, and so on.

该段话大意是:窗口在任何线程中都可以创建,但消息循环必须要和创建窗口在同一线程,否则窗口将无法从DispatchMessage()获取任何消息!
    
    原来如此,最重要是这么一句:It is important to note that the message loop and window procedure for the window must be in the thread that created the window.
    
    好吧,那么我们在支线程中放置消息循环代码,看看是什么结果吧:

#include "windows.h"HWND g_hWnd = NULL;
HINSTANCE g_hInst;LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{return DefWindowProc(hWnd,wMsg,wParam,lParam);
}void CreateWnd(void)
{    WNDCLASS wc = {0};wc.style         = 0;wc.lpfnWndProc   = WndProc;wc.cbClsExtra    = 0;wc.cbWndExtra    = 0;wc.hInstance     = g_hInst;wc.hIcon         = NULL; wc.hCursor       = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);wc.lpszMenuName  = NULL;wc.lpszClassName = TEXT("SimpleWindow");RegisterClass(&wc);g_hWnd = CreateWindowEx(0,TEXT("SimpleWindow"),TEXT("SimpleWindow"),WS_VISIBLE,0,0,200,200,NULL, NULL, g_hInst, 0);
}DWORD CreateThread(PVOID pArg)
{CreateWnd();//The message loop
    MSG msg;while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}int WINAPI WinMain(    HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR    lpCmdLine,int       nCmdShow)
{// TODO: Place code here.
    g_hInst = hInstance;HANDLE hThrd = CreateThread(NULL,0,CreateThread,NULL,0,NULL);CloseHandle(hThrd);MSG msg;while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}

一切正常,如同在主线程创建一样!
    
    当然了,还有点需要注意的,在这个例子中,由于消息循环在主线程和分线程都分别存在,如果在WndProc()调用PostQuitMessage(),那么退出的也仅仅是分线程,而主线程还是会不停地在等待消息,从而导致程序无法正常退出.不过倒不用过分担心,和这个示例代码不同,在实际代码编写中,在主线程往往都会创建主窗口,而在这个主窗口消息处理函数调用PostQuitMessage()则完全可以让主线程正常退出.
    
    事实告诉我们,非主线程创建窗口也能工作正常,只要我们注意一点:消息循环必须要和创建窗口在同一线程!

原文地址: http://blog.csdn.net/norains/article/details/2023957

转载于:https://www.cnblogs.com/likebeta/archive/2012/09/21/2696622.html

在非主线程中创建窗口相关推荐

  1. TApplicaiton.ProcessMessages不能在非主线程使用

    本文仅是实验和实证的结果.(深层原因需要有机会了解ProcessMessages的实现) 1.缘起 Hotfox在移植到BCB环境下,以支持客户端开发后,在应用开发测试时发现:移植的本地管理模块在增加 ...

  2. C语言:记录在主线程中停止子线程

    主线程中创建一个子线程如代码: #include <stdio.h> #include <pthread.h> #include <unistd.h> #inclu ...

  3. android handler 主线程吗,[android开发]非主线程进行handler操作

    [android开发]非主线程进行handler操作 (2012-10-30 16:26:01) 标签: 杂谈 android默认对主线程创建有消息队列及looper(looper是对消息队列的操作类 ...

  4. 【Android 异步操作】Android 线程切换 ( 判定当前线程是否是主线程 | 子线程中执行主线程方法 | 主线程中执行子线程方法 )

    文章目录 一.判定当前线程是否是主线程 二.子线程中执行主线程方法 三.主线程中执行子线程方法 一.判定当前线程是否是主线程 在 Android 中 , 如果要判定当前线程是否是主线程 , 可以使用如 ...

  5. 【Android 异步操作】Handler ( 主线程中的 Handler 与 Looper | Handler 原理简介 )

    文章目录 一.主线程中的 Handler 与 Looper 二.Handler 原理简介 一.主线程中的 Handler 与 Looper Android 系统中 , 点击图标启动一个应用进程 , 就 ...

  6. Handler-接受子线程数据更新UI主线程;非主线程通信--HandlerThread

    一.定义 主要接受子线程发送的数据, 并用此数据配合主线程更新UI.           解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI ...

  7. python主线程执行_在Django vi中的主线程中执行Python函数

    我创建了Django视图"graph",目的是显示从matplotlib.pyplot模块.我编写了我的函数plot\u bubbles(返回amatplotlib.figure. ...

  8. [译]不要在UI主线程中进行耗时的操作

    原文: Why Ice Cream Sandwich Crashes your App 问题 自Android Ice Cream Sandwich发布后, 这个问题就开始在StackOverflow ...

  9. [转]Android限制只能在主线程中进行UI访问的实现原理

    目录 Android限制只能在主线程中进行UI访问 Thread的实现 Android Thread 的构造方法 Android Thread 的start()方法 如何在我们自己的代码中去检测当前T ...

最新文章

  1. 解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题
  2. mysql 安装 注意点
  3. TCP/IP的四元组 五元组 七元组
  4. java real football_Java学习--设计模式之行为型模式(三)
  5. 首次使用Windbg调试dNet程序
  6. FastDFS工具类的使用
  7. 7-2 地下迷宫探索 (30 分)(C语言实现)
  8. SpringCloud:学习 Docker安装Consul,注册服务
  9. python 之 ------- 协程(微线程)
  10. SQL2008数据类型
  11. 5.文件操作 --- 系统调用
  12. HTML5块元素标签的使用
  13. sqlmap安装和使用
  14. TendaU12无线网卡Linux驱动,解决Centos7 安装腾达U12无线网卡驱动问题
  15. 机器学习:AI数据集划分(训练集、验证集、测试集)
  16. 1-3(中文版)语法和词性总结
  17. 二十一世纪大学英语读写教程学习笔记(原文)——2 - Conversational Ballgames(对话风格与球类运动)
  18. 小象学院python网课值得吗-小象学院Python数据分析第二期【升级版】
  19. 转:PM产品设计九步法
  20. 浏览器禁用cookie后session还能用吗?cookie与session区别

热门文章

  1. oracle ocp笔记(1)
  2. hadoop集群崩溃恢复记录
  3. 优化器--牛顿法总结
  4. COGS 930. [河南省队2012] 找第k小的数 主席树
  5. delphi实现两个目录路径的链接
  6. PHP排序算法的复习和总结
  7. UITabBarController 和 UINavigationController 的详解
  8. Linux基本命令(1)管理文件和目录的命令
  9. build.xml编译报错Specified VM install not found: type Standard VM, name jdk1.7.0_45
  10. 结合JDK源码看设计模式——桥接模式