WarmGUI(2) 类CWndApp山寨CWinApp
自从打算开发一个框架之后,我就没睡好过觉,需要学习思考的东西太多,尤其是水平比较低的时候更加难了。目前虽然开发出来些东西,感觉思路还是有些乱,慢慢都发出来,请教各位高人吧,还是那句话:千里之行始于足下。MFC中CWinApp类主要做程序的初始化和终止前的清理,并且继承了CWinThread,
class CWinApp : public CWinThread
CWinThread处理与线程相关的一些事务,例如创建线程、挂起和恢复线程、设定线程的优先级,向一个线程发送消息,等等。
而CWinThread又从CCmdTarget继承,
class CWinThread :
public CCmdTarget
CCmdTarget处理OLE,TypeLib这样的一些事务。
但是我并不打算让App类做这样的继承,理由是
1. 作为一个普通的WinApp,可能没有机会处理线程或者OLE的事务,
2. 并不一定需要用继承的关系,用组合的关系或许更好,用@溪流 的话来说,没事不用继承的好,
3. 快速的迭代开发
因此上我把CWndApp的功能暂时局限在初始化和退出应用两个函数上,线程是很重要的,我打算以后实现一个CThread类,而OLE,TypeLib之类的事务,也放在以后来实现,并且可以借鉴@溪流 现在对原生OLE的探索工作。这样看来CWndApp非常简单,但是他和 CWindow类配合应该能够满足最小的应用框架:
1
class WARMGUI_API CWndApp
2 {
3 public:
4 CWndApp( void);
5 virtual ~CWndApp( void);
6
7 int UniqueInstance(TCHAR * appname);
8
9 virtual int InitialApp(HINSTANCE hInstance, int nCmdShow);
10
11 virtual void CleanupApp();
12
13 protected:
14 HANDLE _hInstanceMutex;
15 HINSTANCE _hInstance;
16 };
2 {
3 public:
4 CWndApp( void);
5 virtual ~CWndApp( void);
6
7 int UniqueInstance(TCHAR * appname);
8
9 virtual int InitialApp(HINSTANCE hInstance, int nCmdShow);
10
11 virtual void CleanupApp();
12
13 protected:
14 HANDLE _hInstanceMutex;
15 HINSTANCE _hInstance;
16 };
其中UniqueInstance函数保证这个应用只运行一个实例,他的实现代码是这样的:
1
int CWndApp::UniqueInstance(TCHAR * appname)
2 {
3 // an instance exists already
4 _hInstanceMutex = OpenMutex(SYNCHRONIZE, TRUE, appname);
5 if (_hInstanceMutex)
6 return (-1);
7
8 // create new instance
9 _hInstanceMutex = CreateMutex(0, FALSE, appname);
10 if (!_hInstanceMutex)
11 return (-2);
12
13 return (0);
14 }
2 {
3 // an instance exists already
4 _hInstanceMutex = OpenMutex(SYNCHRONIZE, TRUE, appname);
5 if (_hInstanceMutex)
6 return (-1);
7
8 // create new instance
9 _hInstanceMutex = CreateMutex(0, FALSE, appname);
10 if (!_hInstanceMutex)
11 return (-2);
12
13 return (0);
14 }
InitialApp是一个虚函数,用来初始化应用,例如下面的实现可以保证使用CListView,设置堆信息,初始化COM接口,另外获得一个ID2D1Factory的实例,这是让Direct2D的初始化,在下一次给出这个类的代码。先看InitialApp的示例:
CleanupApp用来做app退出之前的清理工作,针对上面的InitialApp,ClanupApp类似这样释放Direct2D的资源:
1
int CWndApp::InitialApp(HINSTANCE hInstance,
int nCmdShow)
2 {
3 INITCOMMONCONTROLSEX InitCtrls;
4 InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX), InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
5 BOOL b = InitCommonControlsEx(&InitCtrls);
6
7 // Ignoring the return value because we want to continue running even in the
8 // unlikely event that HeapSetInformation fails.
9 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
10 CoInitialize(NULL);
11
12 CDxFactorys::GetInstance()->InitDxFactory();
13 return (0);
14 }
2 {
3 INITCOMMONCONTROLSEX InitCtrls;
4 InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX), InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
5 BOOL b = InitCommonControlsEx(&InitCtrls);
6
7 // Ignoring the return value because we want to continue running even in the
8 // unlikely event that HeapSetInformation fails.
9 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
10 CoInitialize(NULL);
11
12 CDxFactorys::GetInstance()->InitDxFactory();
13 return (0);
14 }
CleanupApp用来做app退出之前的清理工作,针对上面的InitialApp,ClanupApp类似这样释放Direct2D的资源:
1
void CWndApp::CleanupApp()
2 {
3 CDxFactorys::GetInstance()->ReleaseResource();
4 CoUninitialize();
5 }
2 {
3 CDxFactorys::GetInstance()->ReleaseResource();
4 CoUninitialize();
5 }
现在一个简单的应用看起来是这样的:
1
int APIENTRY _tWinMain(HINSTANCE hInstance,
2 HINSTANCE hPrevInstance,
3 LPTSTR lpCmdLine,
4 int nCmdShow)
5 {
6 CWndApp app;
7 if (app.UniqueInstance(L"MyTestWndApp"))
8 return (0);
9
10 app.InitialApp(hInstance, nCmdShow);
11
12 CMyWindow mainwnd;
13 TCHAR szTitle[MAX_LOADSTRING] = L"MyFirstWindow";
14 TCHAR szClassName[MAX_LOADSTRING] = L"WARMGUIWNDCLASS";
15
16 BOOL r = mainwnd.InitInstance(hInstance, hPrevInstance, lpCmdLine, nCmdShow, szClassName, szTitle);
17 if (r)
18 mainwnd.RunMessageLoop(0);
19
20 app.CleanupApp();
21 return (r) ? 0 : -1;
22 }
2 HINSTANCE hPrevInstance,
3 LPTSTR lpCmdLine,
4 int nCmdShow)
5 {
6 CWndApp app;
7 if (app.UniqueInstance(L"MyTestWndApp"))
8 return (0);
9
10 app.InitialApp(hInstance, nCmdShow);
11
12 CMyWindow mainwnd;
13 TCHAR szTitle[MAX_LOADSTRING] = L"MyFirstWindow";
14 TCHAR szClassName[MAX_LOADSTRING] = L"WARMGUIWNDCLASS";
15
16 BOOL r = mainwnd.InitInstance(hInstance, hPrevInstance, lpCmdLine, nCmdShow, szClassName, szTitle);
17 if (r)
18 mainwnd.RunMessageLoop(0);
19
20 app.CleanupApp();
21 return (r) ? 0 : -1;
22 }
现在确实很简单,或许应该增加更多的函数,不过貌似一个典型的Win32 App的应用框架已经有点样子了。 现在还有很重要的HDC, Bitmap, Font, Brush等绘图的一大坨东西,不过我并不打算封装他们到类里来,因为这不是WarmGUI的重点,因为即将开始进入DirectX的世界,一个我目前还比较陌生的世界,一边学习一边前进吧 ^_^