<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>窗口句柄</title>
	<atom:link href="https://www.aitaocui.cn/tag/268407/feed" rel="self" type="application/rss+xml" />
	<link>https://www.aitaocui.cn</link>
	<description>翡翠玉石爱好者聚集地</description>
	<lastBuildDate>Tue, 29 Nov 2022 05:27:41 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.1.1</generator>

<image>
	<url>https://www.aitaocui.cn/wp-content/uploads/2022/11/taocui.png</url>
	<title>窗口句柄</title>
	<link>https://www.aitaocui.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>窗口句柄(计算机数据结构)</title>
		<link>https://www.aitaocui.cn/article/380771.html</link>
					<comments>https://www.aitaocui.cn/article/380771.html#respond</comments>
		
		<dc:creator><![CDATA[横眉冷对千夫指]]></dc:creator>
		<pubDate>Tue, 29 Nov 2022 05:27:41 +0000</pubDate>
				<category><![CDATA[知识]]></category>
		<category><![CDATA[窗口句柄]]></category>
		<guid isPermaLink="false">https://www.aitaocui.cn/?p=380771</guid>

					<description><![CDATA[在Windows中，句柄是一个系统内部数据结构的引用，对象可以映射到唯一的句柄，句柄也可以映射到唯一的对象。如当你操作一个窗口，或说是一个Delphi窗体时，系统会给你一个该窗口的...]]></description>
										<content:encoded><![CDATA[</p>
<article>
<p>在Windows中，句柄是一个系统内部数据结构的引用，对象可以映射到唯一的句柄，句柄也可以映射到唯一的对象。如当你操作一个窗口，或说是一个Delphi窗体时，系统会给你一个该窗口的句柄，系统会通知你“你正在操作142号窗口”，就此你的应用程序就能要求系统对142号窗口进行操作——移动窗口、改变窗口大小、把窗口最小化等等。实际上许多Windows API函数把句柄作为它的第一个参数，如GDI（图形设备接口）句柄、菜单句柄、实例句柄、位图句柄等，不仅仅局限于窗口函数。换句话说，句柄是一种内部代码，通过它能引用受系统控制的特殊元素，如窗口、位图、图标、内存块、光标、字体、菜单等。</p>
</article>
<article>
<h1>案例</h1>
<p>获取窗口句柄</p>
<p>案例说明</p>
<p>本例实现窗口句柄的获取。</p>
<p>实现过程</p>
<p>Private Declare Function GetWindowLong Lib user32 Alias GetWindowLongA (ByVal hwnd As Long, ByVal nIndex As Long) As Long</p>
<p>Private Declare Function SetWindowLong Lib user32 Alias SetWindowLongA (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long</p>
<p>Private Declare Function SetLayeredWindowAttributes Lib user32 (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long</p>
<p>Private Const WS_EX_LAYERED = H80000</p>
<p>Private Const GWL_EXSTYLE = (-20)</p>
<p>Private Const LWA_ALPHA = H2</p>
<p>Private Sub Form_Activate()</p>
<p>On Error Resume Next</p>
<p>For i = 0 To 150 Step 2.5</p>
<p>SetLayeredWindowAttributes Me.hwnd, 0, i, LWA_ALPHA</p>
<p>DoEvents</p>
<p>Next i</p>
<p>End Sub</p>
<p>Private Sub Form_load()</p>
<p>Dim rtn As Long</p>
<p>rtn = GetWindowLong(Me.hwnd, GWL_EXSTYLE)</p>
<p>rtn = rtn Or WS_EX_LAYERED</p>
<p>SetWindowLong Me.hwnd, GWL_EXSTYLE, rtn</p>
<p>SetLayeredWindowAttributes Me.hwnd, 0, 0, LWA_ALPHA</p>
<p>End Sub</p>
<h1>概念</h1>
<p>单从概念上讲，句柄指一个对象的标识，而指针是一个对象的内存首地址。从实际处理的角度讲，即可以把句柄定义为指针，又可以把它定义为同类对象数组的索引，这两种处理方法都有优缺点，至于选用哪种方式，完全应该看实际需要，这可以说是一种程序设计上的技巧。那种单纯认为句柄是指针或索引的想法都是机械的、不确切的。</p>
<p>其实，在Windows中类似的处理是很多的、很灵活的。再举个相似的例子：</p>
<p>我们知道，在Windows中有个函数叫做CallWindowProc。顾名思义，它的作用就是向指定的窗口过程传递一个消息。你也许会想，既然我已经有了窗口过程的指针，为什么我不可以直接通过这个指针调用该函数（这是C语言的内建功能）？事实上，在Win16中确实可以这么做，因为GetWindowLong返回的确实是该函数的指针。但在Win32下，GetWindowLong返回的并不是该函数的指针，而是一个包含函数指针的数据结构的指针（MSDN上说返回的是一个窗口函数地址或它的句柄，就是指的这种情况）。该数据结构是可变的，但只要你使用CallWindowProc来调用的话是不会出错的。这里我们又看到使用句柄处理带来的好处。（补充说明一点：微软在这里之所以这么处理，是为了解决16位/32位以及ANSI/UNICODE的转化问题）</p>
<h1>解疑</h1>
<h2 id="a-2b1f9875">定义</h2>
<p>句柄是什么？</p>
<p>在windows中，句柄是和对象一一对应的32位无符号整数值。对象可以映射到唯</p>
<p>一的句柄，句柄也可以映射到唯一的对象。</p>
<h2 id="a-b48fd773">用途</h2>
<p>为什么我们需要句柄？</p>
<p>更准确地说，是windows需要句柄。windows需要向程序员提供必要地编程接口</p>
<p>，在这些接口中，允许程序员访问、创建和销毁对象。但是，出于封装地考虑，wi</p>
<p>ndows并不想向程序员返回指针。指针包含了太多的信息。首先指针给出了对象存储</p>
<p>的确切位置；其次，要操作一个指针，程序员必须知道指针所指对象的内部结构特</p>
<p>征，也即，windows必须向程序员暴露相应的数据结构，而这些数据结构也许是操作</p>
<p>系统想向程序员隐藏的。</p>
<p>如果说COM技术向用户隐藏了数据，只暴露了接口并只允许按接口定义的方法操</p>
<p>作数据的话，句柄这种方式则允许你按自己的方式直接操作数据，但windows又不向</p>
<p>你直接暴露数据。直接操作数据是程序员需要的，不暴露数据是windows所需要的，</p>
<p>句柄封装方式实现了各取所需。</p>
<h2 id="a-e29984ab">映射</h2>
<p>句柄如何与对象映射</p>
<p>封装背后，必须有一个地方可以实现解码，以实现句柄和对象的相互转换。在</p>
<p>windows中，存在两种映射方式：</p>
<p>a. 全等映射。也即，句柄本身就是一个指针。映射在这里只是类型转换而已。</p>
<p>这种情况有，进程实例句柄或模块句柄，以及资源句柄等等。</p>
<p>b. 基于表格的映射。这是对象指针与句柄之间最普通的映射机制。操作系统创</p>
<p>建表格，并保存所有要考虑的对象。需要创建新对象时，要先在表格中找到空入口</p>
<p>，然后把表示对象的数据添入其中。当对象被删除时，它的数据成员和其在表中的</p>
<p>入口被释放。</p>
<h2 id="a-a8442ca3">实现</h2>
<p>句柄的定义和实现</p>
<p>我们以GDI对象为例进行讨论。创建了GDI对象，就会得到该对象的句柄。句柄</p>
<p>的对象可能是HBRUSH、HPEN、HFONT或HDC中的一种，这依赖于你创建的GDI对象类</p>
<p>型。但是最普通的GDI对象类型是HGDIOBJ。HGDIOBJ被定义成空指针。</p>
<p>HPEN的实际编译类型定义随编译时间宏STRICT的不同而不同。如果STRCIT已经</p>
<p>被定义了，HPEN是这样的：</p>
<p>struct HPEN__ {int unused};</p>
<p>typedef struct HPEN__ HPEN;</p>
<p>如果STRICT没有定义，HPEN是这样定义的：</p>
<p>typedef void HANDLE;</p>
<p>typedef HANDLE HPEN;</p>
<p>上面这段代码是一个注重细节的程序员最接近句柄的地方，因此我们重点分析</p>
<p>一下。这里有一点点技巧。如果定义了STRICT宏，HPEN是指向有单个未使用字段的</p>
<p>结构的指针，否则HPEN是空指针。C/C++编译器允许把任何类型的指针作为空指什传</p>
<p>递，反之则不可以。两个不同类型的非空指针是互不兼容的。在STRICT版本中，编</p>
<p>译对GDI对象句柄的不正确混用将给出警告，对于非GDI句柄，如HWND、HMENU的不正</p>
<p>确混用也会给出警告，从而使程序在编译器得到更STRICT的检查。</p>
<p>接下来的分析可能不那么令你感兴趣，但它更深刻地揭示了句柄。对GDI句柄来</p>
<p>说，尽管windows头文件把它定义成指针，但如果你仔细检查这些句柄的值，它根本</p>
<p>就不像指针，这也是为什么我说它只是一个32位无符整数值的原因。对句柄就是指</p>
<p>针的情况，这句话也仍然适用。让我们随意地生成一些句柄，比如你用GetStockOb</p>
<p>ject()以得到一些句柄，你会发现，它们的值总在区间0x01900011到0xba040389。</p>
<p>前者指向用户区中的未分配的无效区域，后者指向内核地址空间。另外你可能发现</p>
<p>，两个句柄之间的值可能只差数值1，这也说明GDI句柄不是指针。</p>
<p>和多数人想象的不一样，句柄也不是一个单纯的索引值。对GDI对象句柄来说，</p>
<p>GDI句柄由8位、1位堆对象标记（表明对象是否创建在堆中）、7位对象类型信息和</p>
<p>高4位为0的16位索引组成，如：</p>
<p>3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0</p>
<p>10 9 8 7 6 5 4 3 2 1 0 98 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0</p>
<p>| 8 位引用计数 |堆 | 对象类型7 | 16位索引 |</p>
<p>标</p>
<p>记</p>
<p>在这里你可以看到，对GDI来说，它只使用了16位作为索引。这意味着一个进程最多只</p>
<p>可以创建小于64K个句柄，实际上受其他一些限制，整个Windows系统中大概可以容纳约</p>
<p>16384(0x4000)个GDI对象。</p>
</article>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.aitaocui.cn/article/380771.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
