什么是 Windows 句柄?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/902967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:24:22  来源:igfitidea点击:

What is a Windows Handle?

windowshandle

提问by Al C

What is a "Handle" when discussing resources in Windows? How do they work?

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

回答by Lawrence Dol

It's an abstract reference value to a resource, often memory or an open file, or a pipe.

它是对资源的抽象引用值,通常是内存或打开的文件或管道。

Properly, in Windows, (and generally in computing) a handle is an abstraction which hides a real memory address from the API user, allowing the system to reorganize physical memory transparently to the program. Resolving a handle into a pointer locks the memory, and releasing the handle invalidates the pointer. In this case think of it as an index into a table of pointers... you use the index for the system API calls, and the system can change the pointer in the table at will.

正确地说,在 Windows 中(通常在计算中)句柄是一种抽象,它对 API 用户隐藏了真实的内存地址,允许系统对程序透明地重新组织物理内存。将句柄解析为指针会锁定内存,释放句柄会使指针无效。在这种情况下,将其视为指向指针表的索引……您将索引用于系统 API 调用,系统可以随意更改表中的指针。

Alternatively a real pointer may be given as the handle when the API writer intends that the user of the API be insulated from the specifics of what the address returned points to; in this case it must be considered that what the handle points to may change at any time (from API version to version or even from call to call of the API that returns the handle) - the handle should therefore be treated as simply an opaque value meaningful onlyto the API.

或者,当 API 编写者希望 API 的用户与返回的地址指向的具体内容隔离时,可以给出一个真实的指针作为句柄;在这种情况下,必须考虑句柄指向的内容可能随时更改(从 API 版本到版本,甚至从返回句柄的 API 的调用到调用) - 因此句柄应被视为简单的不透明值仅对API有意义。

I should add that in any modern operating system, even the so-called "real pointers" are still opaque handles into the virtual memory space of the process, which enables the O/S to manage and rearrange memory without invalidating the pointers within the process.

我应该补充一点,在任何现代操作系统中,即使是所谓的“真实指针”仍然是进程虚拟内存空间的不透明句柄,这使操作系统能够管理和重新排列内存,而不会使进程内的指针失效.

回答by Dan Moulding

A HANDLEis a context-specific unique identifier. By context-specific, I mean that a handle obtained from one context cannot necessarily be used in any other aribtrary context that also works on HANDLEs.

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

For example, GetModuleHandlereturns a unique identifier to a currently loaded module. The returned handle can be used in other functions that accept module handles. It cannot be given to functions that require other types of handles. For example, you couldn't give a handle returned from GetModuleHandleto HeapDestroyand expect it to do something sensible.

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

The HANDLEitself is just an integral type. Usually, but not necessarily, it is a pointer to some underlying type or memory location. For example, the HANDLEreturned by GetModuleHandleis actually a pointer to the base virtual memory address of the module. But there is no rule stating that handles must be pointers. A handle could also just be a simple integer (which could possibly be used by some Win32 API as an index into an array).

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

HANDLEs are intentionally opaque representations that provide encapsulation and abstraction from internal Win32 resources. This way, the Win32 APIs could potentially change the underlying type behind a HANDLE, without it impacting user code in any way (at least that's the idea).

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

Consider these three different internal implementations of a Win32 API that I just made up, and assume that Widgetis a struct.

考虑我刚刚编写的 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);
}

The first example exposes the internal details about the API: it allows the user code to know that GetWidgetreturns a pointer to a struct Widget. This has a couple of consequences:

第一个示例公开了有关 API 的内部细节:它允许用户代码知道GetWidget返回一个指向struct Widget. 这有几个后果:

  • the user code must have access to the header file that defines the Widgetstruct
  • the user code could potentially modify internal parts of the returned Widgetstruct
  • 用户代码必须有权访问定义Widget结构的头文件
  • 用户代码可能会修改返回Widget结构的内部部分

Both of these consequences may be undesirable.

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

The second example hides this internal detail from the user code, by returning just void *. The user code doesn't need access to the header that defines the Widgetstruct.

第二个示例通过仅返回void *. 用户代码不需要访问定义Widget结构的标头。

The third example is exactly the same as the second, but we just call the void *a HANDLEinstead. Perhaps this discourages user code from trying to figure out exactly what the void *points to.

第三个示例与第二个示例完全相同,但我们只是调用void *aHANDLE代替。也许这会阻止用户代码试图弄清楚到底void *指向什么。

Why go through this trouble? Consider this fourth example of a newer version of this same API:

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

typedef void * HANDLE;

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

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

Notice that the function's interface is identical to the third example above. This means that user code can continue to use this new version of the API, without any changes, even though the "behind the scenes" implementation has changed to use the NewImprovedWidgetstruct instead.

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

The handles in these example are really just a new, presumably friendlier, name for void *, which is exactly what a HANDLEis in the Win32 API (look it up at MSDN). It provides an opaque wall between the user code and the Win32 library's internal representations that increases portability, between versions of Windows, of code that uses the Win32 API.

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

回答by Nick Haddad

A HANDLE in Win32 programming is a token that represents a resource that is managed by the Windows kernel. A handle can be to a window, a file, etc.

Win32 编程中的 HANDLE 是表示由 Windows 内核管理的资源的标记。句柄可以是窗口、文件等。

Handles are simply a way of identifying a particulate resource that you want to work with using the Win32 APIs.

句柄只是一种识别要使用 Win32 API 使用的特定资源的方法。

So for instance, if you want to create a Window, and show it on the screen you could do the following:

因此,例如,如果您想创建一个窗口,并将其显示在屏幕上,您可以执行以下操作:

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

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

In the above example HWND means "a handle to a window".

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

If you are used to an object oriented language you can think of a HANDLE as an instance of a class with no methods who's state is only modifiable by other functions. In this case the ShowWindowfunction modifies the state of the Window HANDLE.

如果您习惯于面向对象的语言,您可以将 HANDLE 视为类的实例,没有方法,其状态只能由其他函数修改。在这种情况下,ShowWindow函数会修改 Window HANDLE 的状态。

See Handles and Data Typesfor more information.

有关更多信息,请参阅句柄和数据类型

回答by sharptooth

A handle is a unique identifier for an object managed by Windows. It's like a pointer, but not a pointerin the sence that it's not an address that could be dereferenced by user code to gain access to some data. Instead a handle is to be passed to a set of functions that can perform actions on the object the handle identifies.

句柄是 Windows 管理的对象的唯一标识符。它就像一个指针,但不是一个指针,因为它不是一个可以被用户代码取消引用以访问某些数据的地址。相反,句柄将传递给一组函数,这些函数可以对句柄标识的对象执行操作。

回答by Edwin Yip

A handle is like a primary key value of a record in a database.

句柄就像数据库中记录的主键值。

edit 1: well, why the downvote, a primary key uniquely identifies a database record, and a handle in the Windows system uniquely identifies a window, an opened file, etc, That's what I'm saying.

编辑1:好吧,为什么downvote,主键唯一标识数据库记录,Windows系统中的句柄唯一标识窗口,打开的文件等,这就是我要说的。

回答by Edwin Yip

So at the most basic level a HANDLE of any sort is a pointer to a pointer or

所以在最基本的层面上,任何类型的 HANDLE 都是指向一个指针或

#define HANDLE void **

Now as to why you would want to use it

现在至于为什么要使用它

Lets take a setup:

让我们做一个设置:

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);
}

So because obj was passed by value (make a copy and give that to the function) to foo, the printf will print the original value of 1.

因此,因为 obj 是按值传递的(制作一个副本并将其提供给函数)到 foo,所以 printf 将打印原始值 1。

Now if we update foo to:

现在,如果我们将 foo 更新为:

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

There is a chance that the printf will print the updated value of 2. But there is also the possibility that foo will cause some form of memory corruption or exception.

printf 有可能打印更新后的值 2。但 foo 也有可能导致某种形式的内存损坏或异常。

The reason is this while you are now using a pointer to pass obj to the function you are also allocating 2 Megs of memory, this could cause the OS to move the memory around updating the location of obj. Since you have passed the pointer by value, if obj gets moved then the OS updates the pointer but not the copy in the function and potentially causing problems.

原因是当您现在使用指针将 obj 传递给函数时,您还分配了 2 Meg 内存,这可能会导致操作系统移动内存以更新 obj 的位置。由于您已按值传递指针,如果 obj 被移动,则操作系统更新指针而不是函数中的副本,并可能导致问题。

A final update to foo of:

foo 的最终更新:

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

This will always print the updated value.

这将始终打印更新的值。

See, when the compiler allocates memory for pointers it marks them as immovable, so any re-shuffling of memory caused by the large object being allocated the value passed to the function will point to the correct address to find out the final location in memory to update.

看,当编译器为指针分配内存时,它会将它们标记为不可移动,因此任何由分配给函数的值的大对象引起的内存重新洗牌都将指向正确的地址,以找出内存中的最终位置更新。

Any particular types of HANDLEs (hWnd, FILE, etc) are domain specific and point to a certain type of structure to protect against memory corruption.

任何特定类型的 HANDLE(hWnd、FILE 等)都是特定于域的,并且指向某种类型的结构以防止内存损坏。

回答by Charlie Martin

Think of the window in Windows as being a struct that describes it. This struct is an internal part of Windows and you don't need to know the details of it. Instead, Windows provides a typedef for pointer to struct for that struct. That's the "handle" by which you can get hold on the window.,

将 Windows 中的窗口视为描述它的结构。这个结构体是 Windows 的内部部分,你不需要知道它的细节。相反,Windows 为该结构的结构指针提供了一个 typedef。那是你可以抓住窗户的“把手”。