- UID
- 4293
- 精华
- 积分
- 11096
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
本帖最后由 系统消息 于 2019-9-3 19:32 编辑
原帖链接:【C语言】裸GDI+ RawGdiplus.h 实现可支持C语言的GDI+调用 https://www.0xaa55.com/forum.php ... 63&fromuid=4293
(出处: 技术宅的结界,转载请保留出处。)
在Windows下最常见的图形接口就是GDI,GDI的功能实在太少了,所以后来微软又开发其扩展版本GDI+。GDI+的功能完善了很多,可是用过GDI+的人都知道,微软提供的GDI+接口都是封装成了类,全部都是面向对象的,因此C语言根本没法使用,然而连基于COM接口的DX都是完全支持C语言的。
不过我在C++用GDI+之前用VB6学过一点,早就知道了GDI+其实也有和Win32API类似的平面API接口,所以从理论上来上GDI+完全是支持C语言的,只不过微软官方没有提供支持C语言的声明(虽然官方的GdiplusFlat.h中有平面API声明,但是里面用了引用传参,并且GDI+对象类型都是class定义的,还有继承关系,无法支持C语言)。所以说需要把GDI+的平面API声明全部翻译一遍才能兼容C语言。
之前我也看过一些别人做的C语言GDI+,他们很多人都喜欢在里面造一些自己轮子,令我不是很满意,更有甚者还用C++写个静态库把GDI+类第三次封装导出C接口(提示一下GDI+平面API是第一次封装,GDI+类是官方做的第二次封装)。所以还是自己来翻译一遍吧,我在这里保证我版本是绝对的纯翻译声明,没有乱加任何自己东西进去,所以我给这个翻译版本叫裸GDI+(也就没有任何第二次封装,直接暴露原生接口)。
不过,既然要翻译成兼容C语言,那么再怎么也有一些地方是需要改动的,所以我还是需要先说明一下:
GDI+头文件里面分成了很多个不对外公开的子头文件,而裸GDI+全部合成在一个头文件中(主要是为了方便发布和使用),因此里面有一些不同头文件中存在相同重复定义的宏我提到头部统一定义一次。
从GDI+的GdiplusGpStubs.h中可以看出,GDI+平面API所用到的类型是带Gp前缀的,而GDI+类的不带(而是靠命名空间区分作用域),所以在裸GDI+中要完全兼容C语言,不能使用C++的任何特性,所以选择大部分类型统一使用Gp前缀开头(有少部分已经带了Gdiplus前缀的类型就不变,还有COM接口类型名和基本数据类型别名不变)。
GdiplusTypes.h中定义了一些值类,如Size、Point、Rect等,它们有内联的成员函数,在裸GDI+中为了兼容C语言,只能将其翻译成内联的全局函数(命名也严格按照GDI+平面API的规则来,以“Gdip类型方法”这种组合形式),有少部分成员函数是直接return成员变量的,我就没有必须搞过来了。对于Rect类的GetLocation、GetSize方法,直接翻译成联合体声明,用联合体成员变量替代即可,而Clone、GetBounds更是没有意义存在,直接两个Rect结构体变量相互赋值就可以了。
同理,GdiplusMetaHeader.h的MetafileHeader类也有GetBounds方法,在裸GDI+中直接把 X Y Width Height 4个INT成员变量改成一个Rect类型的Bounds成员变量代替(反正要用XY的时候用Bounds.一下也能出来)。
在GdiplusPixelFormats.h中的PixelFormat是typedef INT,并且其常量都是拿宏定义,在裸GDI+中干脆就一起翻译成枚举了。
在GdiplusColor.h中的Color类,有GetAlpha、GetRed、GetGreen、GetBlue等方法,同样也在裸GDI+中翻译成的联合体成员,还有结构体类中定义的枚举也提取出来放在了全局,通过加前缀来代替作用域。
在GdiplusImaging.h中有个IImageBytes的COM对象,因此按DX声明COM接口的方式实现C语言和C++双向兼容。同理GdiplusAbort抽象接口翻译时也做响应的改动。
GDI+1.1的GdiplusEffects.h中,有关特效第二次封装的类全部去掉,仅保留平面API部分。
GdiplusGpStubs.h中使用class定义的GDI+对象类型,为了兼容C语言翻译成了struct定义,并且在C++条件编译下保持其继承关系(不过我稍微改动一点的就是,利用纯虚析构函数和私有构造函数保证不能被用户实例化),C语言环境则只提供struct前置声明,不定义实体来保证不被用户实例化,但是由于C语言没有继承关系,所以父类类型只好定义成void的别名了,只有这样才能保持子类*可以隐式转父类*的特性(虽然说不同类型指针转换C语言编译器不报错,但是为了避免编译器报警告,正好又可以让父类*隐式转子类*时能出警告)。还有一点就是在GDI+中,GdiplusGpStubs.h的包含在GdiplusEffects.h的后面,而在裸GDI+中,为了同时定义C语言和C++双兼容对象类型,用条件编译的宏,所以为了方便只好把GdiplusGpStubs.h的内容提前了。
GdiplusFlat.h中的平面API声明中,有一小部分函数使用引用传参,为了兼容C语言,所以翻译成了指针类型按地址传参,但又为了在C++环境下保留其特性(所以加了条件编译在C++下重载一个引用传参的版本)。还有就是GdipCreateFontFromLogfont(A/W)和GdipGetLogFont(A/W)这4个API,GDI+没有提供通用编码声明(即像绝大多数Win32API那样随编译器编码环境自动切换A或W模式),我翻译的时候也就只好加进去了(C语言下根据编译器环境自动切换A/W,C++下直接学GDI+类使用重载自动区分A/W)。
由于这里仅做声明翻译,不是算个人作品,因此最终解释权仍然归微软公司所有,头文件中保留微软公司的版权信息。
附件压缩包中,提供 RawGdiplus.h 、测试Demo(main.c和test.exe)、tree.png(来自DXSDK)。
|
|