每次要进行windows编程时都要写结构,虽然可以用windows自己生成,但是实在太乱。只好自己简单的包装一个CApp类。以后需要时,只要继承该类即可。写完后直接如下调用:
#include "stdafx.h"
#include "MyApp.h"
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR m_lpCmdLine,
int m_nCmdShow )
{
CMyApp app(hInstance,m_lpCmdLine, m_nCmdShow);
app.Run();
}
其中CMyApp继承自CApp类。
设计基类时,本来想参考下MFC的设计模式,后来发现MFC实在藏的太深,我还没那个水平完全按照那个结构搞出来。只好自己琢磨一下简易版本的。
基类名我定为R3DApp,首先设计成员变量和成员函数,在头文件中如下描述:
class R3DApp
{
public:
R3DApp(HINSTANCE hInstance,LPSTR m_lpCmdLine, int m_nCmdShow);
virtual ~R3DApp(void);
static void CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT InitApp(); //初始化windows基本信息,比如注册类,建立窗口
void Run(); //开始消息循环
virtual void Loop(void){}; // 消息循环中需要的内容
virtual void InitInstance( void ); // 初始化子类需要的内容
virtual void GameMsgProcess( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); //处理消息
protected:
HWND m_hWnd;
HINSTANCE m_hInstance ;
LPSTR m_lpCmdLine ;
int m_nCmdShow ;
int m_nPosX;
int m_nPosY;
int m_nWidth;
int m_nHeight;
HICON m_hIcon;
HICON m_hSmIcon;
HCURSOR m_hCursor;
LPCSTR m_szWindowsName;
};
我将windows开始结构的几个部分分开了。讲经常需要添代码的地方设置为虚函数,供继承重写。成员变量主要保存windows的信息,都会先初始话,若子类需要修改某个参数,只要再子类的构造函数中修改参数即可。这里windows参数我只保存常用的,该类仅仅用来测试。
本来我想将InitApp()函数直接放进基类的构造函数中,不过这样的话,因为基类构造函数先与子类构在函数执行,所以就算再子类的构造函数中修改了成员变量中的windows参数,也无法对InitApp产生影响。只好让子类再修改数值后再调用该函数。其中的WinProc一定要申明为static因为它是CALLBACK函数。至于什么叫callback函数,以及为什么callback函数作为类成员必须是static类型的,在候俊杰的深入浅出第二版的298页有详细解释。
接下来写具体代码。其实需要写的也就三个函数 InitApp,Run,以及winProc函数。实现如下:
static R3DApp *g_pMe;
void R3DApp::Run()
{
MSG uMsg;
ZeroMemory( &uMsg, sizeof(MSG));
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
{
Loop();
}
}
}
LRESULT R3DApp::InitApp()
{
WNDCLASSEX winClass;
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = (WNDPROC)WindowProc;
winClass.hInstance = m_hInstance;
winClass.hIcon = m_hIcon;
winClass.hIconSm = m_hSmIcon;
winClass.hCursor = m_hCursor;
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if (!RegisterClassEx(&winClass) )
{
return E_FAIL;
}
m_hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",
m_szWindowsName,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
m_nPosX, m_nPosY, m_nWidth, m_nHeight, NULL, NULL, m_hInstance, NULL );
if( m_hWnd == NULL )
{
return E_FAIL;
}
InitInstance();
ShowWindow( m_hWnd, m_nCmdShow );
UpdateWindow( m_hWnd );
return S_OK;
}
void CALLBACK R3DApp::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
g_pMe->GameMsgProcess(hWnd, msg, wParam, lParam); //GameMsgProcess(hWnd, msg, wParam, lParam);
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
{
DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
}
其中虚函数的调用已经用蓝字标出。我用红字标出的地方卡了我2天没有解决,后来最后还是在csdn论坛问人才解决的。这个地方的难点是因为winproc是static的,而GameMsgProcess是虚函数,无法申明为static。想解决这个问题,只能进行间接调用。首先要在全局变量声名static R3DApp *g_pMe,然后在基类构造函数中初始化为this指针,这样就可以在winproc中调用GameMsgProcess了。
到这里类已经设计完了。子类继承后在3个虚函数中添入所需代码,然后直接实例化后,run就可以了。
ps:由于作者水平有限,只写了个小框架,可能有些地方还有问题。也没有做什么错误处理,该类仅用来学习。