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

这篇具有很好参考价值的文章主要介绍了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博客文章来源地址https://www.toymoban.com/news/detail-772067.html

到了这里,关于c++游戏小技巧9:windows.h 句柄介绍+实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++游戏小技巧12:输入输出流(存读档超全版)

    目录 1.前言 2.输入/输出概念 3.流的概念 4.正文 1.标准I/O流 1.get()函数  2.getline()函数 3.read()函数  4.ignore()函数 5.gcount()函数 6.peek()函数 7.putback()函数 8.istream集合栗子 9.put()函数 10.write()函数 11.ostream集合栗子 2.文件I/O流 1.流的关闭 2.缓冲区类型 3.设置缓冲区属性 4.缓冲区清空

    2024年02月13日
    浏览(43)
  • 【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧

     [导读]本系列博文内容链接如下: 【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动 【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C++】做一个飞

    2024年02月11日
    浏览(53)
  • windows使用FindWindow函数查找窗口句柄

    理解什么是句柄? 对于“句柄”,之前一直停留在一知半解的认识层面,也说不清具体概念,只知道它是一个 标识符 ,用来标记对象或者说某个东西的。只知其名不知其意。目前学习windows编程,对“ 句柄 ”做一个完整的认。 现在先看一张图(这张图是从其他博主博文扒下

    2024年02月06日
    浏览(41)
  • 【一些随笔】浅析 Linux和Windows:系统介绍、操作差异与使用技巧解析

    Linux和Windows系统的操作差异; Linux系统介绍、系统监控和优化技巧、Shell脚本编程技巧、一些命令使用技巧; Windows系统介绍、优化和加速技巧、一些在Windows系统下常用的快捷键; 在使用Linux和Windows时,有一些事情可能在Linux上较为顺理成章,而在Windows上可能令人费解。比如

    2024年02月13日
    浏览(45)
  • Windows 10 X64 内核对象句柄表解析

    fweWindows 很多API函数都会创建和使用句柄(传入参数),句柄代表一个内核对象的内存地址,每个进程都有一个句柄表,它保存着进程拥有的句柄,内核也有一个句柄表 PspCidTable,它保存着整个系统的句柄。 ExpLookupHandleTableEntry windows内核句柄表结构解析 句柄表结构 进程句柄表位

    2024年02月06日
    浏览(86)
  • 真正理解微软Windows程序运行机制——什么是句柄

    我是荔园微风,作为一名在IT界整整25年的老兵,今天说说Windows程序的运行机制。经常被问到MFC到底是一个什么技术,为了解释这个我之前还写过帖子,但是很多人还是不理解。其实这没什么,我在学生时代也被这个问题困绕过。而且那个时间学习资料没有那么丰富,网上也

    2024年02月04日
    浏览(39)
  • 【C++】做一个飞机空战小游戏(六)——给两架飞机设置不同颜色(cout输出彩色字符、结构体使用技巧)

      [导读]本系列博文内容链接如下: 【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动 【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C++】做一个飞

    2024年02月14日
    浏览(44)
  • C# Windows API应用:获取桌面所有窗口句柄的方法

    C# Windows API应用:获取桌面所有窗口句柄的方法 在 C# 的 Windows 应用程序开发中,我们常常需要获取桌面上所有窗口的句柄,以便进行一些窗口管理或者后续操作。本文将介绍一种利用 Windows API 获取桌面所有窗口句柄的方法,并提供相应的源代码和描述。 在开始之前,我们需

    2024年02月05日
    浏览(50)
  • Net 高级调试之三:类型元数据介绍(同步块表、类型句柄、方法描述符等)

    一、简介 今天是《Net 高级调试》的第三篇文章,压力还是不小的。上一篇文章,我们浅浅的谈了谈 CLR 和 Windows 加载器是如何加载 Net 程序集的,如何找到程序的入口点的,有了前面的基础,我们今天看一点更详细的东西。既然 Windows 操作系统已经加载了 CLR,初始化了应用程

    2024年02月08日
    浏览(39)
  • 【游戏】PC游戏引擎简介及游戏使用技术检测技巧

    从事游戏安全行业多年,各种游戏引擎让人眼花缭乱,对游戏分析肯定也想了解相关引擎特点,这样才能更好的进行下一步的分析。 今天就将PC上常见的引擎及作品进行介绍,并介绍一些工具去快速了解一个新游戏。 先看一个steam上游戏引擎统计数据 https://steamdb.info/tech/。

    2024年02月07日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包