1.封装WinMain至动态链接库
DND的前言:
DND是定位于Windows平台的2d游戏引擎,使用C++和DirectX 11实现,编译器使用vs2015。保留了一些3d功能,适合做一些pc上的高效率2d游戏。目前已经是第n遍重写引擎代码了(n>= 5),在这次重写的机会,也以发博客的方式记录自己的学习笔记,同时也希望我所分享的一些技术能帮助到大家。
本章前言:
在windows编程下,一般项目以控制台窗口、Windows窗口、动态链接库、静态链接库四种形式为目标生成。DND引擎使用动态链接库的方式生成,而使用DND引擎的程序直接建立Windows窗口(即入口函数为WinMain)。虽然可以选择以main作为入口,但是一开始出现的控制台窗口并不好处理掉(隐藏掉还是会闪一下,程序员们怎么能忍,一下格比就下去了)。所以比较好的方式是以WinMain作为入口,然后再建立Console窗口作为调试信息窗口(这个窗口可选是否建立,一般调试的时候建立,发布后肯定不需要建立了)。但是作为引擎必须将WinMain封装起来,HGE引擎就没有处理这一点,导致使用难度提高了不少:-),想想我大一的时候。
最终效果:
用户建立Win32项目之后,只需要如下使用便可实现程序入口:
//main.cpp
#include <DND.h>
DNDMain()
{
//主函数内容
}
//endmain.cpp
实现过程:
由于使用链接库的程序(后面称为用户程序)是Win32窗口程序,它需要查找WinMain函数符号作为函数入口。但我们将其放入了动态链接库,如下面所示:
//WinMain的定义式,放在了DND的项目中
#include <windows.h>
int WINAPIWinMain(HINSTANCEhinstance, HINSTANCE,LPSTR, int)
{
//一些内容
}
//end
所以我们需要导出函数符号,右键项目文件->添加新建项->代码->模块定义文件(.def)。在def文件中添加导出WinMain,内容如下所示:
//export.def
LIBRARY"DND"
EXPORTS
WinMain
//end export.def
这样入口就会从库中的WinMain入口函数执行。但是为了WinMain函数执行我们形式入口函数,需要从用户执行模块取得形式入口函数指针。这里用到了GetProcAddress函数,WinMain函数内容如下:
int WINAPIWinMain(HINSTANCEhinstance, HINSTANCE,LPSTR, int)
{
void(*_func_dnd_main)(void);
//从执行模块获取_func_dnd_main函数
_func_dnd_main = (void(*)())GetProcAddress(hinstance,"_func_dnd_main");
if (!_func_dnd_main)
{
//错误处理
return 0;
}
//执行形式入口函数
_func_dnd_main();
return 0;
}
注意,在这里这个函数名字叫_func_dnd_main,当然你也可以随便写,只要各处统一就行了。在执行形式入口函数之前或之后,还可以执行引擎相关的一些函数,保证在用户的代码执行之前或之后执行。
接着,我们需要在用户程序中实现这个_func_dnd_main函数的定义,也就是形式入口函数。像下面这样:
extern "C"__declspec(dllexport)void _func_dnd_main()
{
}
其中extern “C”让函数名以C的方式编译,__declspec(dllexport)使这个函数从用户程序中导出。为了简化写法,再定义一个宏DNDMain:
#defineDNDMainextern"C"__declspec(dllexport)void _func_dnd_main
这样,形式入口函数的写法就变成了最终效果中的写法,用起来十分简单。
示例:
打上一个断点,可以发现程序执行到了我们想执行的地方,并且整个程序也只有5行。眼花了,8行:-)。
作者:略游
日期:17-05-20
QQ:1339484752