跟创建普通的win32窗口一样,线程中的窗口也需要注册和窗口处理过程

// Test_WM_CLOSE.cpp : Defines the entry point for the application.
// #include "framework.h"
#include "Test_WM_CLOSE.h"
#include <thread> #define MAX_LOADSTRING 100 // Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND hWnd;
HWND g_hWnd;
HWND button;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc1(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
void CreateWndInThread(int nWidth, int nHeight); 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. // Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_TESTWMCLOSE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); // Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
} HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWMCLOSE)); MSG msg; // Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} return (int) msg.wParam;
} //
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
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_TESTWMCLOSE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_TESTWMCLOSE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex);
} //
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable 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;
} //
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
std::thread t(CreateWndInThread, 960, 480);
t.detach();
}
break;
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_LBUTTONDOWN:
{
SendMessage(g_hWnd, WM_CLOSE, 0, 0);
}
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;
} LRESULT CALLBACK WndProc1(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch (wMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, wMsg, wParam, lParam);
}
} void CreateWndInThread(int nWidth, int nHeight)
{
WNDCLASSEXA wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc1;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(nullptr);
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL; char cName[MAX_PATH] = { 0 };
GetModuleFileNameA(wcex.hInstance, cName, sizeof(cName));
char* szApp = strrchr(cName, '\\') + 1;
strchr(szApp, '.')[0] = '\0'; wcex.lpszClassName = szApp;
wcex.hIconSm = 0;
RegisterClassExA(&wcex); g_hWnd = CreateWindowA(szApp, nullptr, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, nWidth, nHeight, NULL, NULL, wcex.hInstance, 0);
button = CreateWindowA("BUTTON", "click", WS_VISIBLE | WS_CHILD, 100, 100, 100, 100, g_hWnd, NULL, wcex.hInstance, 0);
ShowWindow(g_hWnd, SW_SHOW);
UpdateWindow(g_hWnd); MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Note: 我在子线程的窗口中又创建了一个按钮控件,如果想要在主线程中关闭按钮窗口,比如在WM_LBUTTONDOWN事件中,我们想点击鼠标左键后,按钮控件被关闭。那么我们需要发送WM_CLOSE消息,因为DestroyWindow无法跨线程关闭窗口。

 case WM_LBUTTONDOWN:
{
SendMessage(g_hWnd, WM_CLOSE, 0, 0);
}

std::thread : 表示一个执行线程。线程允许多个功能并发执行。 (C++11起)

detch: 允许线程独立于线程句柄执行

win32 - 创建子线程中的窗口的更多相关文章

  1. Windows:子线程中创建窗口

    一般来讲,UI的所有操作都必须在主线程,否则会出现未知错误.但有时候我们会需要一个功能比较单一的窗口,同时希望他在一个单独的线程运行.并不影响主线程的效率. 下面说明一下新建子线程创建的新窗口的方法, ...

  2. MFC在子线程中创建窗口(PostMessage方法)

    1.创建子线程 C++创建线程的方式比较多 1)最简单易用的<thread>头文件,但是这种方法创建的子线程中无法给主线程PostMessage消息(也可能是我操作有误,总之没成功) 2) ...

  3. C# WebService中任务处理线程创建子线程后

    protected void WriteLog(string message) { lock (lockObject) { var file = System.IO.File.AppendText(& ...

  4. C# 在窗体的子线程中创建新窗体

    在子线程中如果简单的调用新窗体的话,新出来的窗体会直接一闪而过.没有停留.效果很差 具体解决方法 如下: 在母窗体中建立委托 public delegate void setShowChartForm ...

  5. 【转载】Delphi7从子线程中发送消息到主线程触发事件执行

    在对数据库的操作时,有时要用一个子线程来进行后台的数据操作.比如说数据备份,转档什么的.在主窗口还能同是进行其它操作.而有时后台每处理一个数据文件,要向主窗口发送消息,让主窗口实时显示处理进度在窗口上 ...

  6. Android中不能在子线程中更新View视图的原因

    这是一条规律,很多coder知道,但原因是什么呢? 如下: When a process is created for your application, its main thread is ded ...

  7. Handler系列之创建子线程Handler

    上一篇我介绍了Handler机制的工作原理,默认情况下,ActivityThread类为我们创建的了主线程的Looper和消息队列,所以当你创建Handler之后发送消息的时候,消息的轮训和handl ...

  8. 在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()

    在子线程中new一个Handler为什么会报以下错误? java.lang.RuntimeException:  Can't create handler inside thread that has ...

  9. Android开发UI之在子线程中更新UI

    转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...

  10. Android 在子线程中更新UI

    今天在做练习时,在一个新开启的线程中调用“Toast.makeText(MainActivity.this, "登陆成功",Toast.LENGTH_SHORT).show();” ...

随机推荐

  1. ext4 磁盘扩容

    目录 ext4文件系统磁盘扩容 目标 途径 操作步骤 改变前的现状 操作和改变后的状态 ext4文件系统磁盘扩容 一个磁盘有多个分区,分别创建了物理卷.卷组.逻辑卷.通过虚拟机软件对虚拟机的磁盘/de ...

  2. [转帖]LSM-Tree:从入门到放弃——入门:基本概念、操作和Trade-Off分析

    https://zhuanlan.zhihu.com/p/428267241 LSM-Tree,全程为日志结构合并树,有趣的是,这个数据结构实际上重点在于日志结构合并,和 tree 本身的关系并不是特 ...

  3. [转帖]mysql8.0的RPM方式安装

    https://www.cnblogs.com/asker009/p/15072354.html 1. 下载 https://dev.mysql.com/downloads/ 使用wget下载yum的 ...

  4. [转帖]Zen4架构+5nm制程+96核心 第四代AMD EPYC处理器强势来袭

    https://new.qq.com/rain/a/20221111A098QE00   不得不承认,技术的持续突破和迭代,使得AMD处理器在近年来得到了"喷气机式"的增长,无论是 ...

  5. 源码学习之Spring容器创建原理

    1 前言 众所周知,Spring可以帮我们管理我们需要的bean.在我们需要用到这些bean的时候,可以很方便的获取到它,然后进行一系列的操作.比如,我们定义一个bean MyTestBean pub ...

  6. 文盘Rust -- r2d2 实现redis连接池

    作者:贾世闻 我们在开发应用后端系统的时候经常要和各种数据库.缓存等资源打交道.这一期,我们聊聊如何访问redis 并将资源池化. 在一个应用后端程序访问redis主要要做的工作有两个,单例和池化. ...

  7. echarts的初始化和销毁dispose

    容器节点被销毁以及被重建时 假设页面中存在多个标签页, 每个标签页都包含一些图表. 当选中一个标签页的时候,其他标签页的内容在 DOM 中被移除了. 这样,当用户再选中这些标签页的时候,就会发现图表& ...

  8. css中使用蒙层会带来哪些问题。

    css中使用蒙层会带来哪些问题. 1==> 如果蒙层设置的背景颜色或者透明度. 蒙层里面的子集元素将会受到影响: 此时子集元素可能不能注册点击的事件. 因为蒙层将它覆盖住了 2==> 此时 ...

  9. kettle系统列文章01---安装与配置

    1).到官网下载需要安装的kettle版本,目前最新版本4.2,官网地址:http://kettle.pentaho.org,我们是使用的版本是kettle3.2 2).本地安装jdk 1.4或以上版 ...

  10. Leetcode 面试题22. 链表中倒数第k个节点 Java语言求解

    题目链接 https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 题目内容 输入一个链表,输出该链 ...