在讨论 Windows 中的资源时,什么是“句柄”?它们如何工作?

有帮助吗?

解决方案

这是一个抽象的参考值,以一个资源,经常存储器或一个打开的文件,或管道。

正确,在Windows中,(通常在计算)手柄是其中隐藏从API用户实际存储器地址,使系统以透明地重新组织的物理存储器的程序的抽象。解析手柄插入指针锁定存储器,和释放手柄上的指针无效。在这种情况下,把它作为一个索引指针表...你使用索引的系统的API调用,并且系统可以随意更改表指针。

可替换地,当API作者的意图是将API的用户从什么样的地址返回点的细节被绝缘的实际指针可以作为把手;在这种情况下,必须考虑到什么样的手柄点随时可能会改变(从API版本的升级,甚至从调用调用返回的句柄的API) - 可以将手柄应被视为仅仅是一个不透明的价值有意义的给API。

我要补充的是在任何现代操作系统,即使是所谓的“真正的指针”仍然不透明句柄到进程的虚拟存储器空间,这使得O / S以管理和没有指针无效重新排列存储器在过程中。

其他提示

A HANDLE 是特定于上下文的唯一标识符。通过上下文特定,我的意思是从一个上下文获得的句柄不一定可以在也适用于的任何其他任意上下文中使用 HANDLEs。

例如, GetModuleHandle 返回当前加载模块的唯一标识符。返回的句柄可以在接受模块句柄的其他函数中使用。它不能提供给需要其他类型句柄的函数。例如,您不能给出从返回的句柄 GetModuleHandleHeapDestroy 并期望它做一些明智的事情。

HANDLE 本身只是一个整型。通常,但不一定,它是指向某些底层类型或内存位置的指针。例如, HANDLE 由返回 GetModuleHandle 实际上是指向模块虚拟内存基地址的指针。但没有规定规定句柄必须是指针。句柄也可以只是一个简单的整数(某些 Win32 API 可能将其用作数组的索引)。

HANDLEs 是故意不透明的表示,提供对内部 Win32 资源的封装和抽象。这样,Win32 API 可能会更改 HANDLE 背后的基础类型,而不会以任何方式影响用户代码(至少是这样的想法)。

考虑我刚刚编写的 Win32 API 的这三种不同的内部实现,并假设 Widget 是一个 struct.

Widget * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return w;
}
void * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<void *>(w);
}
typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

第一个示例公开了有关 API 的内部详细信息:它允许用户代码知道 GetWidget 返回一个指向 a 的指针 struct Widget. 。这会带来几个后果:

  • 用户代码必须有权访问定义了的头文件 Widget 结构体
  • 用户代码可能会修改返回的内部部分 Widget 结构体

这两种后果都可能是不可取的。

第二个示例通过仅返回来对用户代码隐藏此内部详细信息 void *. 。用户代码不需要访问定义的标头 Widget 结构。

第三个例子与第二个例子完全相同,但我们只是调用 void * A HANDLE 反而。也许这会阻碍用户代码尝试弄清楚到底是什么 void * 指着。

为什么要经历这个麻烦?考虑同一 API 的新版本的第四个示例:

typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    NewImprovedWidget *w;

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

请注意,该函数的接口与上面的第三个示例相同。这意味着用户代码可以继续使用这个新版本的 API,无需任何更改,即使“幕后”实现已更改为使用 NewImprovedWidget 结构代替。

这些示例中的句柄实际上只是一个新的、可能更友好的名称 void *, ,这正是 HANDLE 位于 Win32 API 中(查找一下 在 MSDN)。它在用户代码和 Win32 库的内部表示之间提供了一道不透明的墙,从而提高了使用 Win32 API 的代码在 Windows 版本之间的可移植性。

在Win32编程的把手是表示由Windows内核管理的资源的令牌。手柄可以是一个窗口,文件,等等。

把手只是要与使用Win32 API的工作标识的颗粒资源的一种方式。

因此,举例来说,如果你想创建一个窗口,并显示它,你可以做到以下几点在屏幕上:

// Create the window
HWND hwnd = CreateWindow(...); 
if (!hwnd)
   return; // hwnd not created

// Show the window.
ShowWindow(hwnd, SW_SHOW);

在上面的例子中HWND的意思是“一个句柄窗口”。

如果你是用你能想到的把手为没有方法谁的状态的类的实例面向对象的语言只有通过其他功能修改。在这种情况下的的ShowWindow 函数修改的窗口句柄的状态。

请参阅把手和数据类型了解更多的信息。

一个手柄是通过视窗管理的对象的唯一标识符。它的像,它是不是通过一些用户代码取消引用来访问某些数据的地址SENCE指针的,但是的不是指针的。代替手柄是将被传递到一组可在手柄识别对象执行的操作的功能。

一个手柄就像在数据库中的记录的主键值。

编辑1:好,为什么downvote,主键唯一标识数据库记录,以及把手在Windows系统中唯一标识一个窗口,打开的文件等,这是我在说什么。

因此,在最基本的级别任何种类的手柄是指向指针的指针或

#define HANDLE void **

现在,为什么你会想使用它

让我们来设置:

class Object{
   int Value;
}

class LargeObj{

   char * val;
   LargeObj()
   {
      val = malloc(2048 * 1000);
   }

}

void foo(Object bar){
    LargeObj lo = new LargeObj();
    bar.Value++;
}

void main()
{
   Object obj = new Object();
   obj.val = 1;
   foo(obj);
   printf("%d", obj.val);
}

因此,因为物镜是由值来传递(进行复制,并给该给函数)为foo时,printf的将打印的1的原始值。

现在,如果我们更新FOO为:

void foo(Object * bar)
{
    LargeObj lo = new LargeObj();
    bar->val++;
}

有一个机会,所述的printf将打印的背景更新值但还存在foo将导致某种形式的内存损坏或异常的可能性。

原因是这样的,当您现在使用指针传递OBJ到正在也分配2个梅格斯的存储器中的功能,这可能会导致OS移动存储器围绕更新obj的位置。既然你已经通过了价值指针,如果obj被那么移动操作系统更新指针,但不是在功能复制和可能导致的问题。

一个最后更新的富:

void foo(Object **bar){
    LargeObj lo = LargeObj();
    Object * b = &bar;
    b->val++;
}

这将总是打印更新值。

请参阅,当编译器分配存储器的指针它它们标记为不可移动的,因此所造成的大对象的存储器中的任何重新洗牌被分配传递给函数的值将指向正确的地址,找出最终位置在存储器更新。

任何特定类型的手柄(HWND,FILE等)是域特定并指向特定类型的结构,以防止存储器的腐败。

在Windows窗口看作是描述它的结构体。这个结构是Windows的一个内部部分,你不需要知道它的细节。相反,Windows提供了指向struct该结构的类型定义。这是“手柄”,通过它可以在窗口上弄个。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top