【问题标题】:Conversion from HGDIOBJ to HBRUSH从 HGDIOBJ 转换为 HBRUSH
【发布时间】:2015-01-05 01:57:04
【问题描述】:

(这个问题是在使用 g++ 编译器的 Win32API 上下文中提出的)。 我很难理解为什么以下代码行不起作用

wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);

wndclass 是 WNDCLASSEX 结构的一个实例,Windows API 明确规定 其成员 hbrBackground 的类型是 HBRUSH。此外,HBRUSH 只是 HANDLE 的 typedef,而 HANDLE 又是 void* 的 typedef。因此,HBRUSH 应该是 void* 类型。 现在,GetStockObject 函数的返回类型是 HGDIOBJ,它也被定义为 HANDLE,因此是 void*。

Windows 数据类型 http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx

GetStockObject http://msdn.microsoft.com/en-us/library/dd144925(v=vs.85).aspx

WNDCLASSEX http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx

为什么编译时会出现以下错误:

invalid conversion from 'HGDIOBJ {aka void*}' to 'HBRUSH' [-fpermissive]

如果我从 GetStockObject 显式转换返回的值,它会起作用

wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

感谢您的帮助。

【问题讨论】:

    标签: c++ winapi g++


    【解决方案1】:

    这是因为 C++ 中不允许来自 void* 的隐式转换(与 C 不同)。

    功能

    HGDIOBJ GetStockObject(int fnObject);
    

    返回定义为void*HGDIOBJ

    typedef void NEAR* HGDIOBJ;
    

    您将其分配给 HBRUSH,这是一个 typedef 指向 struct 的指针

    struct HBRUSH__;
    typedef struct HBRUSH__ *HBRUSH;
    

    (见windef.h

    虽然这样的赋值在 C 中可以正常工作,但在 C++ 中,您应该显式转换:

    wndclass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    

    见:void pointers: difference between C and C++

    编辑:

    正如 jensa 在 cmets 中指出的,文章 Windows Data Types 已经过时了。这是委婉的说。我不记得它到底是什么时候发生的,但几十年来默认启用STRICT Type Checking。这篇文章可能写于上个世纪(20 世纪)。

    这是yic8110/7/2012的评论引述

    这篇文章需要审核。 上次审核是什么时候? 15年前? 语句 typedef HANDLE HINSTANCE;是完全不正确的,因为很多 其他 typedef HANDLE。其中绝大多数现在是 DECLARE_HANDLE() 结构。请查看并修复这篇文章。请参阅此 KB83456 http://support.microsoft.com/kb/83456(最后更新于 1999 年 11 月) 更多详情

    您还可以在此处了解有关STRICT 的更多信息及其优势:STRICT Type Checking

    这是windef.h中的样子:

    DECLARE_HANDLE(HBRUSH);
    

    DECLARE_HANDLE下面的某个地方定义为:

    #ifdef STRICT
    typedef void *HANDLE;
    #if 0 && (_MSC_VER > 1000)
    #define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
    #else
    #define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
    #endif
    #else
    typedef PVOID HANDLE;
    #define DECLARE_HANDLE(name) typedef HANDLE name
    #endif
    

    默认情况下,我们使用第 6 行中的 DECLARE_HANDLE。使用 NO_STRICT -- 第 9-10 行。

    【讨论】:

    • 我明白了,谢谢你的回答。但是,在我提供的链接(Windows 数据类型)中,它清楚地说: typedef HANDLE HBRUSH;此文档是否已过时?
    • @jensa 这取决于是否定义了STRICT。如果是,则 Win32 不透明对象类型具有不同的类型。如果不是,他们都是void*。在当前标头中,STRICT 默认定义为1,除非定义了NO_STRICT
    • @jensa 我通过添加一些关于STRICT 的信息改进了我的答案。
    • @Drop 感谢您的更新,特别是关于非常过时的 Windows 数据类型文档页面的信息。从现在开始我会查看头文件!
    【解决方案2】:

    在 C++ 术语中,您可以说 GetStockObject 返回 GDIBase*,并且它需要强制转换为适当的派生类转换(例如,假设 HBrushGDI)。因此,您必须进行类型转换。

    class GDIBase;
    class HBrushGDI : GDIBase;
    GDIBase* GetStockObject(int);
    
    
    HBrushGDI* pBrush;
    pBrush = static_cast<HBrushGDI*>GetStockObject(WHITE_BRUSH);
    

    这与对从GetProcAddress 返回的函数指针进行类型转换相同。因此,类型转换为适当的类型是安全的(假设您知道正确的类型)。

    【讨论】:

      猜你喜欢
      • 2011-04-06
      • 1970-01-01
      • 2021-08-15
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 2016-06-13
      • 1970-01-01
      • 2011-12-10
      相关资源
      最近更新 更多