最近研究了一下 wxWidgets 跨平台开发,先是花了个把星期看了一下 c++ 语言。然后就是实战,毕竟只有实际动手才能真正了解掌握一样,因此做了一个很简单的 RESTful CLIENT 小项目。

wxWidgets 确实是相当优秀的一个跨平台开发库。c++ 不存在内存自动回收的机制,因此所有 wxWidgets 的类都有相应的资源管理方式,基本上由 wxWidgets 提供的组件是不需要你手动去 delete ,管理释放的。窗口类,线程类都会在执行完或被关闭时自己回收。对于界面布局有提供各种的 wxSizer 可以帮助你跟据窗口的大小自动调整控件的位置和大小。wxString 也提供了基本的转换,格式化功能。各种基础设施,做一些简单的界面应用绝对地足够了。

当然,不尽如人意的地方也很多。比如没有提供完善路径处理的函数,如 node.js/go 等都有提供的 path.join 功能。有提供 xml 处理功能,但没有 json 支持。有提供 http client 功能,但没有 https/cacert 之类的支持。

json 支持可以通过 jsoncpp 实现。使用的姿势跟 javascript 的很接近,上手很方便。要注意的是这个东东貌似只能在 stack 上使用,不支持 new 到 heap 上。因此,当函数返回时,相关的对象就会被释放,造成无效指针。在设计 API CLIENT 时就不能直接返回 JSON 对象。而是要返回 string 格式,再在后续处理函数中 parse 后再处理。这货还有一个更坑的地方是,当你把一个 json object bar 赋值给另外个 json object foo 后,你再修改 bar 的值,是不会反应到 foo 中的。所以当要更新某个子节点上的值,那是要把所有的父节目都牵涉进来才能达成。 看看这个:

1
2
3
4
5
Json::Value foo, bar;
bar["name"] = "bar";
foo["bar"] = bar;
bar["name"] = "foobar";
// foo = { bar: "bar" }

如何得到想要的:

1
foo["bar"]["name"] = "foobar";

但是你以为可以这样:

1
2
Json::Value bar = foo["bar"];
bar["name"] = "foobar"; // no, it's not gonna work.

除非你再把 bar 再赋值给 foo:

1
foo["bar"] = bar; // unless you assign bar to foo once again.

所以 c++ 虽然可以重载操作符,但强大也会容易带来混淆,使阅读代码变得困难。

虽然 wxWidgets 有 wxHttp 可以用于发送 http 请求,但这货太简陋了,连个 ssl 支持都没有,更不用讲对 自颁发证书 的支持。最后还是选用了 libcurl 来进行 http 请求。优点是功能强大,各种支持都不是问题。要说有不太爽的地方,那就是这货是个 c 库。听说有个 wxCURL 项目,也许下回可以试用一下。

整个过程中最坑的要数 Visual Studio C++ 了。一般来讲,当你修改了源码之后,按 F5 这时编译器应该是把相应源文件的 .obj 删除,重新编译,重新链接成新的可执行文件(当然没改动的源文件对应的 .obj 是不重新编译的),然后执行新的文件。当我在测试 wxSizer 布局的行为时,发现改来改去界面都他喵的没有变化,曾一度以为是 wxSizer 的 bug。于是果断改成绝对布局的方式。折腾了很久之后,才发现必须是 clean project/solution 之后再运行才能生效。于是很奇怪,google 了一大轮,有的说是项目设计中的 build 勾没打上,有的说是没分 hpp/cpp 的问题。各种尝试都是解决不了我的问题。后面通过观测 build log 。发现我改动的 obj 确实会被重新生成,然后 linker 也有出一个什么鬼 warnning 信息,但就是出来的 build 一直是之前的!通过不停地尝试,发现只有修改了 main.cpp 的代码,或删除 main.obj 会才使 vc 重新连接整个程序。这个若说是 visual studio 的 bug (2008 和 2015 都有相同的情况),那应该不会只有我一个人遇到,诡异的是 google 来 google 去确实没人有讲到相同的情况。难道我是地球上最后一个还在使用 vs 做 c++ 的人吗?最后实在没办法,只能在 prebuild 脚本里加上删除 mail.obj 命令。否则每次都要整个项目 rebuild 也是很麻烦的事情,花费时间长不讲,还经常忘了 clean 导致以为修改的代码有问题。

最后就是打包,由于我主要用的是 visual studio 2008 express 版本,不带有打包安装程序的功能。于是便采用了 wix 对程序进行打包,过程也是各种曲折。wix 的文档真是太差劲了,各种代码片断讲得不清不楚。sample 也少得可怜。

也许 c++ 是太古老了,很多编程方式都与现在流行的理念差左太大。各种资料也是不好找,挺费劲的。