Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何检查;“类型”;运行时Win32句柄的_C++_Winapi_C++11 - Fatal编程技术网

C++ 如何检查;“类型”;运行时Win32句柄的

C++ 如何检查;“类型”;运行时Win32句柄的,c++,winapi,c++11,C++,Winapi,C++11,我必须在C++11中为Win32句柄(如HFONT、HWND、HMODULE等)编写一个引用计数包装类。我想使用一个WinHandle类隐式地强制转换到所有句柄类型(都是void*typedef)。不幸的是,所有句柄都有不同的函数来销毁底层对象,例如DestroyWindow()、CloseHandle()、DeleteObject()等等,因此我需要为每个句柄类型使用不同的类来实现相应的销毁函数。(这将是47个类+基类,包括用户对象、gdi对象和内核对象) 那么,有没有一种方法可以在运行时确定

我必须在C++11中为Win32句柄(如HFONT、HWND、HMODULE等)编写一个引用计数包装类。我想使用一个WinHandle类隐式地强制转换到所有句柄类型(都是void*typedef)。不幸的是,所有句柄都有不同的函数来销毁底层对象,例如DestroyWindow()、CloseHandle()、DeleteObject()等等,因此我需要为每个句柄类型使用不同的类来实现相应的销毁函数。(这将是47个类+基类,包括用户对象、gdi对象和内核对象)

那么,有没有一种方法可以在运行时确定句柄是哪种类型的,或者更确切地说,需要调用哪种函数?(在文档中,我只找到了isWindow()函数)


我已经考虑过使用RTTI或调用所有delete函数,直到其中一个成功。RTTI不起作用,因为所有句柄类型都是void*的typedef,因此是相同的。后者可能会工作,但所有句柄都必须是唯一的才能正常工作(没有一个GDI句柄可以与用户句柄或内核句柄具有相同的值),否则它可能会导致错误和内存泄漏

如果您只需要一个引用计数的句柄,为什么不直接使用
shared\u ptr

例如:

shared\u ptr文件(CreateFile(L“la.txt”、GENERIC\u WRITE、file\u shared\u READ、NULL、CREATE\u ALWAYS、file\u ATTRIBUTE\u NORMAL、NULL)、CloseHandle);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
它不会在你的代码中留下很大的足迹,你也不必编写40个类


通过为每种类型的关闭定义一些函数,可以避免每次传递相关的关闭函数,例如:

auto make_handle_CloseHandle = [](HANDLE h){ return  (shared_ptr<void>(h,CloseHandle)); };

auto file = make_handle_CloseHandle(CreateFile(L"la.txt", /*same ...*/));

DWORD written;
WriteFile(   file.get(), //get handle
            "ABC\r\n", 
            5,
            &written, 
            NULL);
auto make_handle_CloseHandle=[](句柄h){return(共享的_ptr(h,CloseHandle));};
auto file=make_handle_CloseHandle(创建文件(L“la.txt”/*相同…*/);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);

并将其放在相关名称空间下的某个头文件中,这样您就不必每次都键入close函数的名称,这些函数的用户就会知道调用了哪个函数(根据
make\u handle.*
name)这可能比仅通过句柄自动识别句柄类型更安全。

如果您只需要一个引用计数的句柄,为什么不直接使用
shared\u ptr

例如:

shared\u ptr文件(CreateFile(L“la.txt”、GENERIC\u WRITE、file\u shared\u READ、NULL、CREATE\u ALWAYS、file\u ATTRIBUTE\u NORMAL、NULL)、CloseHandle);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
它不会在你的代码中留下很大的足迹,你也不必编写40个类


通过为每种类型的关闭定义一些函数,可以避免每次传递相关的关闭函数,例如:

auto make_handle_CloseHandle = [](HANDLE h){ return  (shared_ptr<void>(h,CloseHandle)); };

auto file = make_handle_CloseHandle(CreateFile(L"la.txt", /*same ...*/));

DWORD written;
WriteFile(   file.get(), //get handle
            "ABC\r\n", 
            5,
            &written, 
            NULL);
auto make_handle_CloseHandle=[](句柄h){return(共享的_ptr(h,CloseHandle));};
auto file=make_handle_CloseHandle(创建文件(L“la.txt”/*相同…*/);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);

并将其放在相关名称空间下的某个头文件中,这样您就不必每次都键入close函数的名称,这些函数的用户就会知道调用了哪个函数(根据
make\u handle.*
name)这可能比仅仅通过句柄自动识别句柄类型更安全。

因为CreateFile的失败结果是无效的句柄值(-1),我不确定这是一个好的解决方案

与其使用一些旨在引用内存地址的内容,不如实现某种共享的_资源或唯一的_资源类型,它接受模板参数或封装包装类型特征的单个参数

我的看起来像这样:

template <typename TRAITS>
struct SharedHandle
{
....
}
struct TestTraits
{
    using HandleType = int;
    static constexpr HandleType INVALID = 0;
    static void Close(HandleType& h)
    {
        h = INVALID;
    }
};

using SharedHandleTestType = SharedHandle<TestTraits>;


TEST(ClvLib_SharedHandle_Tests, SharedHandle_default)
{
    auto tt = SharedHandleTestType();

    EXPECT_FALSE(tt);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_good)
{
    auto tt = SharedHandleTestType(1);

    EXPECT_TRUE(tt);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_use)
{
    auto tt = SharedHandleTestType(1);

    auto result = [](int t)->int {return t + 1; }(tt);
    auto expected = tt.Get() + 1;

    EXPECT_EQ(expected, result);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy1)
{
    auto tt = SharedHandleTestType(1);
    auto t2 = tt;

    EXPECT_TRUE(tt);
    EXPECT_TRUE(t2);

    tt = 0;

    EXPECT_FALSE(tt);
    EXPECT_TRUE(t2);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy2)
{
    auto tt = SharedHandleTestType(1);
    auto t2 = tt;

    EXPECT_TRUE(tt);
    EXPECT_TRUE(t2);

    tt = 0;

    EXPECT_FALSE(tt);
    EXPECT_TRUE(t2);

    t2.Release();

    EXPECT_FALSE(tt);
    EXPECT_FALSE(t2);
}
模板
结构SharedHandle
{
....
}
它的用法如下:

template <typename TRAITS>
struct SharedHandle
{
....
}
struct TestTraits
{
    using HandleType = int;
    static constexpr HandleType INVALID = 0;
    static void Close(HandleType& h)
    {
        h = INVALID;
    }
};

using SharedHandleTestType = SharedHandle<TestTraits>;


TEST(ClvLib_SharedHandle_Tests, SharedHandle_default)
{
    auto tt = SharedHandleTestType();

    EXPECT_FALSE(tt);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_good)
{
    auto tt = SharedHandleTestType(1);

    EXPECT_TRUE(tt);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_use)
{
    auto tt = SharedHandleTestType(1);

    auto result = [](int t)->int {return t + 1; }(tt);
    auto expected = tt.Get() + 1;

    EXPECT_EQ(expected, result);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy1)
{
    auto tt = SharedHandleTestType(1);
    auto t2 = tt;

    EXPECT_TRUE(tt);
    EXPECT_TRUE(t2);

    tt = 0;

    EXPECT_FALSE(tt);
    EXPECT_TRUE(t2);
}

TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy2)
{
    auto tt = SharedHandleTestType(1);
    auto t2 = tt;

    EXPECT_TRUE(tt);
    EXPECT_TRUE(t2);

    tt = 0;

    EXPECT_FALSE(tt);
    EXPECT_TRUE(t2);

    t2.Release();

    EXPECT_FALSE(tt);
    EXPECT_FALSE(t2);
}
struct TestTraits
{
使用HandleType=int;
静态constexpr HandleType无效=0;
静态空隙闭合(手柄类型和h)
{
h=无效;
}
};
使用SharedHandleteType=SharedHandle;
测试(ClvLib_SharedHandle_测试,SharedHandle_默认)
{
auto tt=SharedHandleteType();
预期错误(tt);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_良好)
{
自动tt=SharedHandleteType(1);
期望真实(tt);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_使用)
{
自动tt=SharedHandleteType(1);
自动结果=[](int t)->int{返回t+1;}(tt);
自动预期=tt.Get()+1;
期望值(期望值、结果);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_copy1)
{
自动tt=SharedHandleteType(1);
自动t2=tt;
期望真实(tt);
期望值为真(t2);
tt=0;
预期错误(tt);
期望值为真(t2);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_副本2)
{
自动tt=SharedHandleteType(1);
自动t2=tt;
期望真实(tt);
期望值为真(t2);
tt=0;
预期错误(tt);
期望值为真(t2);
t2.释放();
预期错误(tt);
期望值为假(t2);
}
对于Windows文件句柄:

struct WinHandleTraits_IHV
{
    using HandleType = HANDLE;
    static constexpr HandleType INVALID = INVALID_HANDLE_VALUE;
    static void Close(HandleType& h)
    {
        CloseHandle(h);
    }
};

using WinFileHandle = SharedHandle<WinHandleTraits_IHV>;
struct WinHandleTraits\u IHV
{
使用HandleType=HANDLE;
static constexpr HandleType INVALID=无效的句柄值;
静态空隙闭合(手柄类型和h)
{
闭合手柄(h);
}
};
使用WinFileHandle=SharedHandle;

由于CreateFile的失败结果是无效的\u HANDLE\u值(-1),因此我不确定这是一个好的解决方案

实现一些