DuplicateHandle 函数 (handleapi.h)

复制对象句柄。

语法

BOOL DuplicateHandle(
  [in]  HANDLE   hSourceProcessHandle,
  [in]  HANDLE   hSourceHandle,
  [in]  HANDLE   hTargetProcessHandle,
  [out] LPHANDLE lpTargetHandle,
  [in]  DWORD    dwDesiredAccess,
  [in]  BOOL     bInheritHandle,
  [in]  DWORD    dwOptions
);

参数

[in] hSourceProcessHandle

包含要复制的句柄的进程句柄。

句柄必须具有PROCESS_DUP_HANDLE访问权限。 有关详细信息,请参阅 进程安全性和访问权限

[in] hSourceHandle

要复制的句柄。 这是在源进程的上下文中有效的开放对象句柄。 有关可以复制其句柄的对象列表,请参阅以下“备注”部分。

[in] hTargetProcessHandle

要接收重复句柄的进程句柄。 句柄必须具有PROCESS_DUP_HANDLE访问权限。

此参数是可选的,如果“选项”中设置了DUPLICATE_CLOSE_SOURCE标志,则可以将此参数指定为 NULL。

[out] lpTargetHandle

指向接收重复句柄的变量的指针。 此句柄值在目标进程的上下文中有效。

如果 hSourceHandleGetCurrentProcessGetCurrentThread 返回的伪句柄, 则 DuplicateHandle 将分别将其转换为进程或线程的实际句柄。

如果 lpTargetHandleNULL,则该函数将复制句柄,但不向调用方返回重复句柄值。 此行为仅用于向后兼容此函数的早期版本。 不应使用此功能,因为目标进程终止之前会丢失系统资源。

如果 hTargetProcessHandleNULL,则忽略此参数。

[in] dwDesiredAccess

为新句柄请求的访问权限。 有关可为每个对象类型指定的标志,请参阅以下“备注”部分。

如果 dwOptions 参数指定DUPLICATE_SAME_ACCESS标志,则忽略此参数。 否则,可以指定的标志取决于要复制其句柄的对象的类型。

如果 hTargetProcessHandleNULL,则忽略此参数。

[in] bInheritHandle

一个指示句柄是否可继承的变量。 如果 为 TRUE,则重复句柄可由目标进程创建的新进程继承。 如果 为 FALSE,则无法继承新句柄。

如果 hTargetProcessHandleNULL,则忽略此参数。

[in] dwOptions

可选操作。 此参数可以是零,也可以是以下值的任意组合。

含义
DUPLICATE_CLOSE_SOURCE
0x00000001
关闭源句柄。 无论返回什么错误状态,都会发生这种情况。
DUPLICATE_SAME_ACCESS
0x00000002
忽略 dwDesiredAccess 参数。 重复句柄具有与源句柄相同的访问权限。

返回值

如果该函数成功,则返回值为非零值。

如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

注解

重复句柄引用与原始句柄相同的对象。 因此,对 对象的任何更改都通过两个句柄反映。 例如,如果复制文件句柄,则两个句柄的当前文件位置始终相同。 对于具有不同文件位置的文件句柄,请使用 CreateFile 函数创建共享同一文件访问权限的文件句柄。

源进程或目标进程 (或源进程和目标进程) ,都可以调用 DuplicateHandle。 例如,进程可以使用 DuplicateHandle 创建可继承句柄的不可继承副本,或具有与原始句柄不同的访问权限的句柄。

源进程使用 GetCurrentProcess 函数获取自身的句柄。 此句柄是伪句柄,但 DuplicateHandle 将其转换为实际进程句柄。 若要获取目标进程句柄,可能需要使用某种形式的进程间通信 (例如,命名管道或共享内存) 将进程标识符传达给源进程。 源进程可以在 OpenProcess 函数中使用此标识符来获取目标进程的句柄。

如果调用 DuplicateHandle 的进程不是目标进程,则源进程必须使用进程间通信将重复句柄的值传递给目标进程。

DuplicateHandle 可用于复制 32 位进程和 64 位进程之间的句柄。 生成的句柄大小适当,以在目标进程中工作。 有关详细信息,请参阅 进程互操作性

DuplicateHandle 可以将句柄复制到以下类型的对象。

Object 描述
访问令牌 句柄由 CreateRestrictedTokenDuplicateTokenDuplicateTokenExOpenProcessTokenOpenThreadToken 函数返回。
更改通知 句柄由 FindFirstChangeNotification 函数返回。
通信设备 句柄由 CreateFile 函数返回。
控制台输入 指定 CONIN$ 时, 由 CreateFile 函数返回句柄;指定STD_INPUT_HANDLE时, 由 GetStdHandle 函数返回句柄。 可以复制控制台句柄,以便仅在同一进程中使用。
控制台屏幕缓冲区 指定 CONOUT$ 时, 由 CreateFile 函数返回句柄;指定STD_OUTPUT_HANDLE时, 由 GetStdHandle 函数返回句柄。 可以复制控制台句柄,以便仅在同一进程中使用。
桌面 句柄由 GetThreadDesktop 函数返回。
事件 句柄由 CreateEventOpenEvent 函数返回。
文件 句柄由 CreateFile 函数返回。
文件映射 句柄由 CreateFileMapping 函数返回。
作业 句柄由 CreateJobObject 函数返回。
Mailslot 句柄由 CreateMailslot 函数返回。
Mutex 句柄由 CreateMutex 或 [OpenMutex] ( 返回。/synchapi/nf-synchapi-openmutexw.md) 函数。
管道 命名管道句柄由 CreateNamedPipeCreateFile 函数返回。 CreatePipe 函数返回匿名管道句柄。
进程 句柄由 CreateProcessGetCurrentProcessOpenProcess 函数返回。
注册表项 句柄由 RegCreateKey、RegCreateKeyExRegOpenKeyRegOpenKeyEx 函数返回。 请注意, RegConnectRegistry 函数返回的注册表项句柄不能用于对 DuplicateHandle 的调用。
Semaphore 句柄由 CreateSemaphoreOpenSemaphore 函数返回。
线程 句柄由 CreateProcessCreateThreadCreateRemoteThreadGetCurrentThread 函数返回
Timer 句柄由 CreateWaitableTimerWOpenWaitableTimerW 函数返回。
事务 句柄由 CreateTransaction 函数返回。
窗口工作站 句柄由 GetProcessWindowStation 函数返回。
 

不应使用 DuplicateHandle 将句柄复制到以下对象:

  • I/O 完成端口。 不会返回错误,但不能使用重复句柄。
  • 套接字。 不会返回错误,但 Winsock 可能无法在目标进程中识别重复句柄。 此外,使用 DuplicateHandle 会干扰基础对象上的内部引用计数。 若要复制套接字句柄,请使用 WSADuplicateSocket 函数。
  • GetCurrentProcessGetCurrentThread 函数返回的伪句柄之外。
dwDesiredAccess 参数指定新句柄的访问权限。 所有对象都支持 标准访问权限。 对象可能还支持其他访问权限,具体取决于对象类型。 有关详细信息,请参阅下列主题: 在某些情况下,新句柄可能具有比原始句柄更多的访问权限。 但是,在其他情况下, DuplicateHandle 无法创建具有比原始权限更多的句柄。 例如,使用GENERIC_READ访问权限创建的文件句柄不能重复,因此它同时具有GENERIC_READ和GENERIC_WRITE访问权限。

通常,当该进程使用句柄完成时,目标进程会关闭重复的句柄。 若要从源进程关闭重复的句柄,请使用以下参数调用 DuplicateHandle

  • hSourceProcessHandle 设置为创建句柄的 DuplicateHandle 调用的目标进程。
  • hSourceHandle 设置为要关闭的重复句柄。
  • hTargetProcessHandle 设置为 NULL
  • dwOptions 设置为 DUPLICATE_CLOSE_SOURCE。

示例

以下示例创建互斥体,将句柄复制到互斥体,并将其传递给另一个线程。 复制句柄可确保增加引用计数,以便在两个线程关闭句柄之前不会销毁互斥对象。

#include <windows.h>

DWORD CALLBACK ThreadProc(PVOID pvParam);

int main()
{
    HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
    HANDLE hMutexDup, hThread;
    DWORD dwThreadId;

    DuplicateHandle(GetCurrentProcess(), 
                    hMutex, 
                    GetCurrentProcess(),
                    &hMutexDup, 
                    0,
                    FALSE,
                    DUPLICATE_SAME_ACCESS);

    hThread = CreateThread(NULL, 0, ThreadProc, 
        (LPVOID) hMutexDup, 0, &dwThreadId);

    // Perform work here, closing the handle when finished with the
    // mutex. If the reference count is zero, the object is destroyed.
    CloseHandle(hMutex);

    // Wait for the worker thread to terminate and clean up.
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    return 0;
}

DWORD CALLBACK ThreadProc(PVOID pvParam)
{
    HANDLE hMutex = (HANDLE)pvParam;

    // Perform work here, closing the handle when finished with the
    // mutex. If the reference count is zero, the object is destroyed.
    CloseHandle(hMutex);
    return 0;
}

要求

要求
最低受支持的客户端 Windows 2000 专业版 [桌面应用 |UWP 应用]
最低受支持的服务器 Windows 2000 Server [桌面应用 |UWP 应用]
目标平台 Windows
标头 handleapi.h (包括 Windows.h)
Library Kernel32.lib
DLL Kernel32.dll

另请参阅

CloseHandle

句柄继承

句柄和对象函数