#TCC编译带通用对话框及资源的简单记事本程序
前些天一直研究`lua`,由此也会关注跟lua很有相似性和相关性的[TCC(Tiny C Compiler)](http://bellard.org/tcc/ "TCC(Tiny C Compiler)")……跟`Lua`一样都是好东西呀~
昨天的时候,由于看到了一篇简单的示例程序[《用C编写的记事本》](http://blog.csdn.net/yueguanghaidao/article/details/6949249 "《用C编写的记事本》"),我突发奇想,想用`TCC`编译它试试……
首先,我们先回顾一下用`gcc`编译这个程序的过程:
```bash
windres note.rc rc.o
gcc -mwindows rc.o note.c -o note.exe -lcomdlg32 -lgdi32
```
先用`windres`编译资源成目标文件,然后把资源和C文件一起编译就行了……因为`gcc`默认关联`kernel32`和`user32`库,所以不用显式添加……
我这边`Windows XP`机器上用`MinGW`编译出来的32位的程序大约有83.6KB……
下面是`TCC`编译的过程,编译出来的32位程序大约28KB,果然小巧的多……
直接编译的话`TCC`会报找不到`OPENFILENAME`结构的定义……
那么首先要把`OPENFILENAME`的定义搞进去,在`gcc`中就是`commdlg.h`文件……
把gcc中的`commdlg.h`拷进去之后,麻烦事就来了,因为`commdlg.h`中引用了另外两个文件`unknwn.h`和`prsht.h`……
这两个文件引入后就会陷入更大的引入陷阱,最后还有各种的`重定义warnning`出现,我们需要想个办法将其规避过去……
那么看这两个文件引入的注释:
```C
#include <unknwn.h> /* for LPUNKNOWN */
#include <prsht.h> /* for HPROPSHEETPAGE */
```
一个是为了引入`LPUNKNOWN`,一个是为了引入`HPROPSHEETPAGE`,仔细看,`HPROPSHEETPAGE`很简单,只需要改成这一行就行:
```C
DECLARE_HANDLE(HPROPSHEETPAGE);
```
可是`LPUNKNOWN`就麻烦了,这是一个结构体指针,而且这个结构体的一些属性还指向其他的结构体,由此牵连`COM组件`以及远程过程调用相关的结构体……
为了避免麻烦,我不再去纠结`LPUNKNOWN`到底是啥了,总之它是一个指针,如果这个指针在我的程序中不会被用到,我大可不必关心这是个啥……
于是定义它为`void *`将其规避过去:
```C
typedef void* LPUNKNOWN;
```
之后编译能够成功,连接就出了问题……因为`tcc`能够默认的关联`gdi32`、`kernel32`和`user32`,所以我们只需要解决`comdlg`库就行……
这个库在`tcc`的lib里是不默认附带的,需要我们手动产生……这就用到了`tcc`自带的,通过dll库到处为lib库的工具`tiny_impdef`……
```bash
tiny_impdef comdlg32.dll
```
该命令会生成`comdlg32.def`,将该文件放在`note.c`同目录里就可以……
由于`comdlg32`是windows默认加载的链接库,所以在执行该命令的时候也不用写路径名……
库和头文件都准备好了,然后就可以进行编译了:
```bash
tcc note.c comdlg32.def
```
编译成功,但是没有链接资源,所以编译之后的exe没有图标,打开之后也没有菜单……这个记事本的功能都在菜单上,没有菜单也是基本不可用的……
关于`tcc`编译资源研究了一下,看`tcc的帮助文档`发现`tcc`本身不能编译`rc资源`,到最后还是要借助`windres`工具先编译成目标文件,然后`tcc`再一起连接……
所以,真正用`tcc`编译该记事本的命令是这样的:
```bash
windres note.rc rc.o
tcc note.c rc.o comdlg32.def
```
具体的整个目录可以[在这里下载查看](https://pan.baidu.com/s/1c1iLw6 "简单记事本程序及源码百度网盘下载路径")~最后编译出来运行的效果大约是这样的:
![简单记事本效果图](demo.png "简单记事本效果图")