Win32 SDK基础(五)之关于窗口类的简单介绍

发布时间 - 2017-06-06 00:00:00    点击率:

一、引言

        在上一文中,我们从零开始创建了一个窗口。其中很重要的一个步骤,就是注册窗口类,如下面的代码:

//注册窗口类
BOOL Register(LPSTR lpClassName, WNDPROC wndProc)
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize = sizeof(wce);
    wce.cbClsExtra = 0;
    wce.cbWndExtra = 0;
    wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wce.hCursor = NULL;
    wce.hIcon = NULL;
    wce.hIconSm = NULL;
    wce.hInstance = g_hInstance;
    wce.lpfnWndProc = wndProc;
    wce.lpszClassName = lpClassName;
    wce.lpszMenuName = NULL;
    wce.style = CS_HREDRAW | CS_VREDRAW;
    ATOM nAtom = RegisterClassEx(&wce);
    if (nAtom == 0)
        return FALSE;
    return true;
}

        Windows下的任何一个窗口,在创建之前都要在系统中已经明确的注册,我们在使用CreateWindowEx进行窗口的创建时,第二个参数的名称就是窗口类名称,这个名称在我们代码可见的作用域内应该是唯一的。本文主要讨论下Windows下,窗口类的问题。

二、窗口类分类

        Windows中所有可见的一切元素基本上都属于一个窗口,不管它的形状如何,是圆的、方的、甚至是无规则的。所有的这些窗口都属于某一个窗口类,大体上来说Windows的窗口类共分为三种:
(1)系统窗口类
(2)全局窗口类
(3)局部窗口类
下面,我将就Windows中窗口类的分类分别进行讨论。

2.1 系统窗口类

        一个按钮、一个编辑框所有这些我们在windows操作系统中可见的控件其实都是一个窗口。当我们安装完操作系统之后,Windows会在操作系统内部注册大量的系统级别的窗口类,我们在进行开发时,可以直接根据窗口类名称创建这些窗口。为了解释这个问题,在上一文中的代码之上,我们引入下面的代码。

HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName)
{
	HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName,
		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL);
	return hWnd;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	// TODO: Place code here.

	g_hInstance = hInstance;
	
	HWND hWnd = CreateMain("Button", "window");
	Display(hWnd);
	Message();
	return 0;
}

        CreateMain是我们定义的一个创建窗口的函数。它接收两个参数,第一个时已经注册的窗口类名称,第二个是窗口的标题。与上一文中的代码不同,我们省去了注册自定义窗口的步骤。而是在WinMain函数中,调用CreateMain创建了一个窗口类名称为“Button”的窗口。我想你已经知道我们要做什么了吧?对,就是要生成一个Button按钮。我们常用的所有控件都已经被操作系统注册成了系统窗口类,我们都可以直接使用。请看下面的程序运行结果:



        你还可以尝试去创建诸如编辑框、下拉框等其他系统级别的窗口。

2.2 全局窗口类

        全局窗口类指注册之后可以在应用程序全局范围内使用的窗口类。比如,我们可以在dll中对全局窗口类进行注册,那么引入该dll的所有程序都可以使用该类。注册全局使用的窗口类时,我们只需要在注册时对wec的结构体的style成员添加CS_GLOBALCLASS属性,如下:

	wce.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;

        为了验证这个问题,我们新添加一个dll项目,然后定义一个如下的窗口注册函数RegisterWindow():

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage返回0
		break;
	default:
		break;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

 BOOL RegisterWindow()
{
	WNDCLASSEX wce = { 0 };
	wce.cbSize = sizeof(wce);
	wce.cbClsExtra = 0;
	wce.cbWndExtra = 0;
	wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wce.hCursor = NULL;
	wce.hIcon = NULL;
	wce.hIconSm = NULL;
	wce.hInstance = NULL;
	wce.lpfnWndProc = WndProc;
	wce.lpszClassName = "DllMain";
	wce.lpszMenuName = NULL;
	wce.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
	ATOM nAtom = RegisterClassEx(&wce);
	if (nAtom == 0)
		return FALSE;
	return true;
}

        RegisterWindow()中注册的窗口类名称为"DllMain",我们在dll的主函数中调用该注册函数完成注册:

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	....
	RegisterWindow();
	return TRUE;
}
}

        在我们的主程序中使用该窗口类创建窗口:

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	...
	HWND hWnd = CreateMain("DllMain", "我是一个Dll注册的窗口");
	Display(hWnd);
	Message();
	return 0;
}

        运行程序你会发现我们也成功生产了这个窗口:



2.3 局部窗口类

        局部窗口类从定义上来说,凡是未在wce的style中添加CS_GLOBALCLASS,而注册的窗口类都是局部窗口类。

wce.style = CS_HREDRAW | CS_VREDRAW;//未添加CS_GLOBALCLASS

       我们在上一文中注册的窗口就是一个局部的窗口类,它的特点就是只能在注册的作用域内使用,由于它和全局窗口类只在注册的style和作用域上有分别,这里就不再详述,如要了解,请参照上一文。


# 上一  # 都是  # 这个问题  # 要在  # 第二个  # 可以直接  # 操作系统  # 我想  # 是在  # 成了 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何实现全文搜索功能?(Scout和Algolia示例)  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  Laravel如何使用Vite进行前端资源打包?(配置示例)  如何在Windows 2008云服务器安全搭建网站?  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  米侠浏览器网页图片不显示怎么办 米侠图片加载修复  html如何与html链接_实现多个HTML页面互相链接【互相】  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  Laravel如何升级到最新版本?(升级指南和步骤)  Laravel怎么配置.env环境变量_Laravel生产环境敏感数据保护与读取【方法】  Laravel如何处理异常和错误?(Handler示例)  Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例  打开php文件提示内存不足_怎么调整php内存限制【解决方案】  如何用PHP快速搭建CMS系统?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  Python进程池调度策略_任务分发说明【指导】  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  公司门户网站制作流程,华为官网怎么做?  如何构建满足综合性能需求的优质建站方案?  制作电商网页,电商供应链怎么做?  Laravel Debugbar怎么安装_Laravel调试工具栏配置指南  Laravel如何为API生成Swagger或OpenAPI文档  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  Laravel中的withCount方法怎么高效统计关联模型数量  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法  音乐网站服务器如何优化API响应速度?  Laravel PHP版本要求一览_Laravel各版本环境要求对照  Android自定义listview布局实现上拉加载下拉刷新功能  Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】  进行网站优化必须要坚持的四大原则  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  Win11怎样安装网易有道词典_Win11安装词典教程【步骤】  Laravel路由怎么定义_Laravel核心路由系统完全入门指南  原生JS获取元素集合的子元素宽度实例  Laravel策略(Policy)如何控制权限_Laravel Gates与Policies实现用户授权  如何自定义建站之星模板颜色并下载新样式?  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  如何在VPS电脑上快速搭建网站?  Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南