调用 ::GetModuleHandleEx unique_ptr具有自定义删除程序以自动处理释放资源

Calling ::GetModuleHandleEx with unique_ptr having custom deleter to handle freeing resources automatically

提问人:Vk0726 提问时间:11/9/2023 最后编辑:Remy LebeauVk0726 更新时间:11/9/2023 访问量:40

问:

我需要在下面的代码中释放吗?HMODULE

DWORD flags =
  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
HMODULE hm = 0;
  ::GetModuleHandleExW(flags, L"Test.dll", &hm);
HRSRC hResource =
  ::FindResourceW(hm, MAKEINTRESOURCEW(TEST1), L"ICON");

if (hResource) {
  HGLOBAL hLoaded = LoadResource(hm, hResource);
  if (hLoaded) {
    size = (int)SizeofResource(hm, hResource);
    auto lpAddress = LockResource(hLoaded);
    //Read resource here
    UnlockResource(hLoaded);
  } else {
    //Error logging
  }
  FreeResource(hLoaded);
} else {
  //Error logging
}

在这里,我在正确的地方释放了大部分资源,除了可能!我需要免费吗?我的理解是,我们在这里只得到而不是加载库,所以我们可能不需要释放它?HMODULEhmHMODULE

如果答案是肯定的,那么我想尝试像我们在这里这样的东西:

将 std::unique_ptr 用于 Windows 句柄

struct Deleter {
    void operator()(HMODULE hModule) const
    {
        if (hModule != nullptr)
        {
            FreeLibrary(hModule);
        }
    }
};

using unique_module = std::unique_ptr<std::remove_pointer<HMODULE>::type, Deleter>;

但是我有点困惑,不知道如何使用这个.unique_module

与此同时,我正在写这个:

HMODULE hm = 0;
unique_module um {hm};

::GetModuleHandleExW(flags, L"Test.dll", &um.get());

虽然我没有编译和测试,但这对我来说似乎是错误的,我需要输入有关如何正确编写此自定义删除器并将其与 一起使用以及如何调用它 .HMODULE::GetModuleHandleEx()

C++ Windows unique-ptr 自定义删除程序

评论

0赞 Raymond Chen 11/9/2023
"检索指定模块的模块句柄,并递增模块的引用计数,除非指定了GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
0赞 Vk0726 11/9/2023
这行得通!但是如何编写自定义删除器并使其与 GetModuleHandleEx 一起使用?我分享的删除程序示例代码,正确吗?

答:

1赞 Remy Lebeau 11/9/2023 #1

首先,您的使用是错误的,因为您没有传递您正在寻找的模块内部的内存地址。如果要按名称查找模块,请不要使用 .在这种情况下,您不妨直接使用,完全不用担心。GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESSGetModuleHandleExW()GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESSGetModuleHandleW()FreeLibrary()

现在,话虽如此......

为了回答您的实际问题,文档说:GetModuleHandleExW()

https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw

检索指定模块的模块句柄,并递增模块的引用计数,除非指定GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT。调用进程必须已加载模块。

...

[in] dwFlags

此参数可以是零,也可以是以下一个或多个值。如果模块的引用计数递增,则调用方必须在不再需要模块句柄时使用 FreeLibrary 函数递减引用计数

所以是的,如果你不使用 ,你需要打电话,例如:FreeLibrary()GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT

HMODULE hm = NULL;
::GetModuleHandleExW(0, L"Test.dll", &hm);
...
FreeLibrary(hm);

如果你想使用自定义来调用,这当然是可行的,但是你无法获取它所持有的指针的地址,所以你必须在你从中构造之前检索 ,例如:unique_ptrDeleterFreeLibrary()unique_ptrHMODULEunique_ptr

HMODULE hm = NULL;
::GetModuleHandleExW(0, L"Test.dll", &hm);
unique_module um {hm};

否则,您可以简单地忘记 ,如果必须使用 ,则直接使用 ,或者只是改用。DeleterGET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNTGetModuleHandleExW()GetModuleHandleW()