c++游戏小技巧9:windows.h 句柄介绍+实例

目录

1.前言

2.正文

1.COORD(结构体)

2.HANDLE(句柄)

3.HWND(句柄)

4.RECT(结构体)

5.CONSOLE_SCREEN_BUFFER_INFO(结构体)

6.point(结构体)

7.代码实例(四个)

1.键鼠操作

2.获得运行框相关信息

3.遍历windows全部可见窗体(执行结果应坤而异)

4.移动运行框

3.后文

1.前言

(关于MFC的事情我在鸽一段时间,主要是实在弄不好)

所以这一期,我们先来进入windows.h······的句柄

全程干货,小心食用

2.正文

1.COORD(结构体)

源码:c++游戏小技巧3:Sleep(停顿) 与 gotoxy(0,0) (无闪清屏)

typedef struct _COORD
{
   SHORT X; // horizontal coordinate
   SHORT Y; // vertical coordinate
} COORD;

COORD 一般用来保存横纵坐标。

所以就有以下的用法:

void gotoxy(int x, int y)//覆盖清屏 ,从指定行列覆盖
{
	COORD pos = {x,y};
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut, pos);
	return ;
}

 (熟不熟悉?gotoxy的更多用法,详见c++游戏小技巧3:Sleep(停顿) 与 gotoxy(0,0) (无闪清屏)​​​​​​)

2.HANDLE(句柄)

 句柄handle是系统资源(或项目)的唯一标识,它的本质是一个指向指针的无类型void指针。用一个16进制表示的32位整数,初步理解为它就是对象在内存中的索引编号。
(百度搜索一下:)

从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄。句柄的英文是"Handle",本义就是"柄",只是在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西拎起一大堆东西,这难道不像是个"柄"吗?

然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义——实实在在地对应内存里地一个地址——所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值引用到一大堆数据的作用,这不是句柄又是什么?

Windows系统中有许多内核对象(这里的对象不完全等价于"面向对象程序设计"一词中的"对象",虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个"对象"的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:

1.暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;
2.操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?

所以,Windows操作系统就采用进一步的间接:在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。

在Windows系统中,这个编号就叫做"句柄"。

Handle在Windows中的含义很广泛,以下关于谈到的Handle除非特别说明,将仅限于进程、线程的上下文中。

1、先来谈谈Handle

Handle本身是一个32位的无符号整数,它用来代表一个内核对象。它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址(一般情况下)。那么Handle的意义何在?它实际上是作为一个索引在一个表中查找对应的内核对象的实际地址。那么这个表在哪里呢?每个进程都有这样的一个表,叫句柄表。该表的第一项就是进程自己的句柄,这也是为什么你调用GetCurrentProcess()总是返回0x7FFFFFFF原因。

简单地说,Handle就是一种用来"间接"代表一个内核对象的整数值。你可以在程序中使用handle来代表你想要操作的内核对象。这里的内核对象包括:事件(Event)、线程、进程、Mutex等等。我们最常见的就是文件句柄(file handle)。

另外要注意的是,Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle(),在多个进程间传递Handle是另外一个话题了,与这里要讨论的无关。

2、进程ID

首先,进程ID是一个32位无符号整数,每个进程都有这样的一个ID,并且该ID在系统范围内是唯一的。系统使用该ID来唯一确定一个进程。

深入些说,系统可能使用进程ID来计算代表该进程的内核对象的基地址(及EPROCESS结构的基地址),具体的计算公式你可以去问微软的OS开发人员。

3、HINSTANCE

HINSTANCE也是一个32无符号整数,它表示程序加载到内存中的基地址。

用法?既然是项目、资源的唯一标识,那肯定用来搞事索引调控对象的位置呀!!!

像gotoxy,里面有两个库函数:

   HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);  获得句柄
   SetConsoleCursorPosition(hOut, pos); 调控句柄

这就是典型的 HANDLE 调控 

3.HWND(句柄)

当一个窗体被创建后,此窗口的窗口句柄也相应被创建,窗体对象的句柄即 "window handle" (HWND)。

强调,HANDLE是资源、项目的唯一标识,但是HWND是窗口的句柄

定义:

HWND hwnd=GetForegroundWindow();

用法:

函数:HWND GetDesktopWindow(void);
功能:获取windows系统桌面的句柄。

函数:BOOL GetWindowRect(HWND, RECT&);
功能:获取窗口的上下左右的位置坐标。

函数:GetConsoleScreenBufferInfo(HANDLE, &CONSOLE_SCREEN_BUFFER_INFO);
功能:获取控制台窗口屏幕缓存的信息。

函数:BOOL IsWindowVisible(HWND);
功能:判断该句柄的对象是否可见。

函数:BOOL IsWindow(HWND);
功能:判断该句柄是否标识一个已存在的窗口。

函数:BOOL MoveWindow(HWND,left,top,width,height,BOOL bRepaint = TRUE);
功能:移动该句柄的对象至指定坐标,并设置对象的宽和高;最后一个参数表示是否重画repaint窗体。

举个栗子:

#include<iostream>
#include<windows.h> 
using namespace std;
 
int main(void)
{
	char s[20];
	char t[]="oh ya";
	SetConsoleTitle(t);
	HWND hwnd=GetForegroundWindow();
	GetWindowText(hwnd,s,sizeof s);
	cout<<s;
	return 0;
}

4.RECT(结构体)

typedef struct tagRECT
{
   LONG left;     //rectangle的左边坐标
   LONG top;      //rectangle的顶边坐标
   LONG right;    //rectangle的右边坐标
   LONG bottom;   //rectangle的下边坐标
} RECT;

用法

函数:BOOL GetClientRect(HWND, RECT&);
功能:获取窗口客户区的上下左右的位置坐标。
提示:客户区是指窗体除了标题,工具,状态,菜单栏等等剩下的区域,包括窗体的边框也是非客户区。

例子

#include<iostream>
#include<windows.h>
using namespace std;
 
int main(void)
{
	int width,height; 
	RECT rect;
	HWND hwnd=GetDesktopWindow();
	char s[256]="",conTitle[256]="Console Test";
	SetConsoleTitle(conTitle);
	GetWindowRect(hwnd,&rect);     
	width=rect.right-rect.left;
	height=rect.bottom-rect.top;
	cout<<"当前桌面分辨率:"<<width<<"*"<<height<<" \b";
	return 0;
}

5.CONSOLE_SCREEN_BUFFER_INFO(结构体)

一个结合体:

typedef struct _CONSOLE_SCREEN_BUFFER_INFO
{
    COORD      dwSize;//屏幕缓冲区的以字符为单位的宽度(X)和高度(Y)
    COORD      dwCursorPosition;//光标在屏幕缓冲区的坐标
    WORD       wAttributes;//绘制文本、背景的颜色等属性
    SMALL_RECT srWindow;//控制台窗口左上角和右下角对应屏幕缓冲区的位置
    COORD      dwMaximumWindowSize;//控制台窗口以字符为单位的最大宽度和高度
}CONSOLE_SCREEN_BUFFER_INFO;

熟不熟悉?COORD!

给个用法

函数:HWND GetNextWindow(HWND, UNIT wCmd);
功能:返回由wCmd指定的窗体句柄;如果窗体不存在,则返回值为NULL。 
参数:wCmd 指定函数返回方式:GW_HWNDNEXT:指定返回下一个窗口的句柄,GW_HWNDPREV:指定返回上一个窗口的句柄;

6.point(结构体)

point一般用来调控鼠标指针

源码:

typedef struct tagPOINT
{ 
    LONG x; //x Specifies the x-coordinate of the point. 
    LONG y; //y Specifies the y-coordinate of the point. 
}POINT; 

系统自带函数:

函数:short GetAsyncKeyState(int nVirtKey);
功能:获取当前是否按下键盘或鼠标上的一个键,对应虚拟键码值nVirtKey。

函数:GetCursorPos(POINT&);
功能:获取鼠标的坐标,与之对应的设定坐标:SetCursorPos(POINT&);

函数:ClipCursor(RECT&);
功能:限定鼠标的活动范围。

常用VK值见这里 c++游戏小技巧2:kd(类型)_L('ω')┘脏脏包└('ω')」的博客-CSDN博客 

7.代码实例(四个)

1.键鼠操作
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;

#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)

void hide()//windows.h
{
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

bool CenterWindow(RECT &rect, RECT &desktop)
{
	int width,height,dtWidth,dtHeight;
	bool bSuccess=false;
	HWND hwnd=GetDesktopWindow();
	GetWindowRect(hwnd,&desktop); 
	dtWidth=desktop.right-desktop.left;
	dtHeight=desktop.bottom-desktop.top;

	hwnd=GetForegroundWindow(); 
	GetWindowRect(hwnd,&rect); 
	width=rect.right-rect.left;
	height=rect.bottom-rect.top;

	bSuccess=MoveWindow(hwnd,(dtWidth-width)/2,(dtHeight-height)/2,width,height,true); 
	GetWindowRect(hwnd,&rect); 
	return bSuccess;
}

void gotoxy(int x, int y)
{
	COORD pos={x,y};
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut, pos);
	return ;
}

int main()
{
	hide();
	int mx,my;
	bool bSuccess=false;
	POINT mouse;//储存鼠标的x,y坐标 
	RECT Rect,rectDesktop;
	char t[]="windows.h库函数鼠标操作测试";
	SetConsoleTitle(t);
	bSuccess=CenterWindow(Rect,rectDesktop);//窗体居中并引用传递回窗体和桌面尺寸
	if(bSuccess)
	{
		gotoxy(12,6);//移动光标 
		cerr<<"窗口已移到屏幕正中间位置!";
	}
	while(1)
	{
		GetCursorPos(&mouse);//获取鼠标位置 
		gotoxy(12,8);
		cerr<<"鼠标的位置坐标(单击左键退出): ";
		if(mouse.x!=mx&&mouse.y!=my) cout<<mouse.x<<"    ,"<<mouse.y<<"    \t";
//		Sleep(1);
		mx=mouse.x;
		my=mouse.y;
		if(kd(VK_LBUTTON)) break;
	}
	gotoxy(16,8);
	cerr<<"已被锁定在控制台所在区域内!(单击右键退出)";
	while(1)
	{
		bSuccess=CenterWindow(Rect,rectDesktop);//窗体居中并引用传递回窗体和桌面尺寸
		ClipCursor(&Rect);
		Sleep(50);
		if(kd(VK_RBUTTON)) ClipCursor(&rectDesktop),exit(0);
	}
	return 0;
}
2.获得运行框相关信息
#include<iostream>
#include<windows.h> 
using namespace std;

void HideCursor()//windows.h
{
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

void gotoXY(short x, short y)
{	//设置光标位置,坐标从左上角(0,0)起始,允许负值 
    COORD position = {x, y};
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hConsole, position);
}
 
int main(void)
{
	HideCursor();
	
	int width,height; 
	RECT rect;
	HWND hwnd=GetDesktopWindow();
	char s[256]="",conTitle[256]="Console Test";
	SetConsoleTitle(conTitle);
	
	GetWindowRect(hwnd,&rect);     
	width=rect.right-rect.left;
	height=rect.bottom-rect.top;
	gotoXY(10,8);
	
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_SCREEN_BUFFER_INFO bInfo;	
	GetConsoleScreenBufferInfo(hConsole, &bInfo);
	
	gotoXY(10,9);
	cout<<"控制台屏幕缓存区大小:"<<bInfo.dwSize.Y<<"行,"<<bInfo.dwSize.X<<"列\t\t\t";
	gotoXY(10,10);
	cout<<"控制台最大显示尺寸:"<<bInfo.dwMaximumWindowSize.Y<<"行,"<<bInfo.dwMaximumWindowSize.X<<"列\t\t\t\t";
	
	hwnd=GetForegroundWindow();	
	while(1)
	{
		gotoXY(bInfo.dwCursorPosition.X,bInfo.dwCursorPosition.Y);
		GetWindowRect(hwnd,&rect);
		cout<<"当前窗口左上角坐标:"<<rect.left<<","<<rect.top<<"\t";
		if(rect.left<-8) break;
		Sleep(3);
	}
	
	gotoXY(0,bInfo.dwCursorPosition.Y+10);
	cout<<"Exit!"<<endl;
	return 0;
}
3.遍历windows全部可见窗体(执行结果应坤而异)
#include<iostream>
#include<windows.h> 
 
using namespace std;
 
int main(void)
{
	int width,height,dtWidth,dtHeight; 
	RECT rect;
	char s[256],conTitle[256]="Console Test <== It\'s me!";
	SetConsoleTitle(conTitle);
	HWND hwnd=GetDesktopWindow();
	GetWindowRect(hwnd,&rect);   //获取桌面大小,即屏幕分辨率 
	dtWidth=rect.right-rect.left;
	dtHeight=rect.bottom-rect.top;
	hwnd=GetNextWindow(hwnd,GW_CHILD);
	
	int i=0;
	while(hwnd!=NULL)
	{ 
		GetWindowText(hwnd,s,sizeof(s));
		if (IsWindowVisible(hwnd)&&strlen(s)>0) //注释掉此行会遍历到几百个(含不可见)窗体
			cout<<++i<<":"<<s<<endl;           //换IsWindow(hwnd)对比一下结果
		hwnd=GetNextWindow(hwnd,GW_HWNDNEXT);
	}
}
4.移动运行框
#include<iostream>
#include<windows.h> 
using namespace std;

void centerwindow(RECT &rect, RECT &desktop)
{//使窗口移动到桌面居中位置 
	int width,height,dtWidth,dtHeight;
	bool bSuccess=false;
	HWND hwnd = GetDesktopWindow();
	GetWindowRect(hwnd,&desktop); 
	dtWidth=desktop.right-desktop.left;
	dtHeight=desktop.bottom-desktop.top;
	
	hwnd = GetForegroundWindow(); 
	GetWindowRect(hwnd,&rect); 
	width=rect.right-rect.left;
	height=rect.bottom-rect.top;
 
	bSuccess=MoveWindow(hwnd,(dtWidth-width)/2,(dtHeight-height)/2,width,height,true); 
	GetWindowRect(hwnd,&rect); 
	return ;
}

int main(void)
{
	int mx,my;
	bool bSuccess=false;
	POINT mouse;   //用来储存鼠标的x,y坐标 
	RECT Rect,rectDesktop;
	centerwindow(Rect,rectDesktop);
}

3.后文

参考文章:C++ <windows.h>库函数探究初步续一:键鼠操作_windows.h vk_Hann Yang的博客-CSDN博客

C++ <windows.h>库函数探究初步:句柄操作_c++ windows.h_Hann Yang的博客-CSDN博客

上一篇:c++游戏小技巧8:MessageBox弹窗_L('ω')┘脏脏包└('ω')」的博客-CSDN博客

下一篇:c++游戏小技巧10:color 颜色_L('ω')┘脏脏包└('ω')」的博客-CSDN博客

  • 21
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值