经过几周的艰苦奋战,终于对飞鸽传书(以下简称FG)的架构有了一个简单的了解,下面分类分析一下各个类的基本情况。
首先是App类。和MFC中其他程序一样,FG中存在着一个App类,用来发送消息,创建和管理窗口等。
main函数如下:
//这里是主函数!!!!!!!!!!!!!!!调用app的run开始执行
//构造函数中有initapp等操作
int WINAPI WinMain(HINSTANCE hI, HINSTANCE, LPSTR cmdLine, int nCmdShow)
{
//建立一个TMsgApp类的对象
TMsgApp app( hI, cmdLine, nCmdShow );
return app.Run();//run函数完成主要的工作,初始化窗口,循环获得和发送消息等
}
TMsgApp是TApp类的子类,TApp类的定义如下:
class TApp
{
protected:
//static的一大堆变量
static TWin **wndArray;
static int wndCnt;
static TWin *SearchWnd(HWND hW);
static BOOL SearchWndIndex(TWin *win, int *index);
static void AddWinSub(TWin *win);
HINSTANCE hCtl3d;
LPSTR cmdLine;
int nCmdShow;
//有一个TWin的mainwnd,指向TMainWin类创建的窗口
TWin *mainWnd;
virtual BOOL InitApp(void);//注意这里的InitApp是虚函数,子类可以重载它
public:
TApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow);
virtual ~TApp();
virtual void InitWindow() = 0;
virtual int Run();
static BOOL PreProcMsg(MSG *msg);
static TWin *preWnd;
static char *defaultClass;
static HINSTANCE hI;
static void AddWin(TWin *win);
static void AddWinByWnd(TWin *win, HWND hWnd);
static void DelWin(TWin *win);
static LRESULT CALLBACK WinProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
实现文件如下:
static char *tapp_id =
"@(#)Copyright (C) H.Shirouzu 1996-2001 tapp.cpp Ver0.95";
#include "tlib.h"
TWin** TApp::wndArray = NULL;
int TApp::wndCnt = 0;
TWin* TApp::preWnd = NULL;
HINSTANCE TApp::hI = NULL;
char* TApp::defaultClass = "tapp";
HINSTANCE LoadCtl3d(void);
TApp::TApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow)
{
hI = _hI;
cmdLine = _cmdLine;
nCmdShow = _nCmdShow;
mainWnd = NULL;
::CoInitialize(NULL);
hCtl3d = LoadCtl3d();
::InitCommonControls();
}
TApp::~TApp()
{
//删除TWin的主窗口指针,注意new是在initApp中new的!!!!!!!!!
delete mainWnd;
if ( hCtl3d )
{
::FreeLibrary(hCtl3d);
}
::CoUninitialize();
}
int TApp::Run(void)
{
MSG msg;
InitApp();
InitWindow();//这里是纯虚拟构造函数!!!
while ( ::GetMessage(&msg, NULL, 0, 0) )
{
if ( PreProcMsg(&msg) )
{
continue;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
BOOL TApp::PreProcMsg(MSG *msg) // for TranslateAccel & IsDialogMessage
{
for ( HWND hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd) )
{
//在WndArray中找到hWnd标志的那个TWin*并将之返回
TWin *win = SearchWnd(hWnd);
if ( win != NULL )
{
return win->PreProcMsg(msg);
}
}
return FALSE;
}
//WNDCLASS窗口类的消息处理函数居然交给TApp的WinProc处理!!!
LRESULT CALLBACK TApp::WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//查找hWnd这个窗口,如果找到了,则调用win窗口的WinProc来处理
TWin *win = SearchWnd( hWnd );
if ( win ) // 找到了,不是第一次加入
{
return win->WinProc(uMsg, wParam, lParam);
}
//是第一次加入,则加入wndarray
//如果是第一次调用TApp::WinProc则加入一个TWin到TWinArray,
//把PreWnd设置为NULL,然后创建一个TWin,
//然后把窗口hWnd赋给win的pWnd,然后调用Win的winproc处理
if ( ( win = preWnd ) != NULL )
{
preWnd = NULL;//把preWnd设置为NULL,以后要用到
//注意win不是NULL!win保存了prewnd原来的值
//这里的hWnd已经create完毕,可以加入到hwndarray中了
AddWinByWnd(win, hWnd);//把hWnd加入array中
//掉用win的WinProc来处理
return win->WinProc(uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void TApp::AddWin( TWin *win )
{
// 仅仅只是把preWnd指向了win
preWnd = win;
}
//把TWin指针的hWnd设置为参数hWnd,然后加入到wndArray中
void TApp::AddWinByWnd(TWin *win, HWND hWnd)
{
win->hWnd = hWnd;
AddWinSub(win);
}
//在wndArray中加入TWin指针 win
void TApp::AddWinSub(TWin *win)
{
if ( SearchWnd ( win->hWnd ) != NULL )
{
return;
}
#define BIG_ALLOC 100
TWin **_wndArray = wndArray;
if ( ( wndCnt % BIG_ALLOC ) == 0 )
{
_wndArray = (TWin **)realloc(wndArray, sizeof(TWin *)
* (wndCnt + BIG_ALLOC));
}
if ( _wndArray == NULL ) // 重新分配空间失败,直接返回
{
return;
}
(wndArray = _wndArray)[wndCnt++] = win;
return;
}
//在wndArray中删除win指定的TWin窗口
void TApp::DelWin(TWin *win)
{
int index;
if ( SearchWndIndex(win, &index) == FALSE )
{
if ( preWnd == win )
{
preWnd = NULL;
}
return;
}
//TWin在TWinArray中存在
// 删除wndArray+index指向的那个指针,后面的所有TWin指针向前移动一格
memmove(wndArray + index, wndArray + index + 1,
sizeof(TWin *) * ( --wndCnt - index ) );
// wndArray = (TWin **)realloc(wndArray, sizeof(TWin *) * wndCnt);
}
BOOL TApp::InitApp(void) // reference kwc
{
WNDCLASS wc;
memset( &wc, 0, sizeof(wc) );
wc.style = (CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_DBLCLKS);
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hI;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = defaultClass;// == "Tapp"
if ( ::FindWindow(defaultClass, NULL) == NULL )
{
if ( ::RegisterClass(&wc) == 0 )
{
return FALSE;
}
}
return TRUE;
}
TWin* TApp::SearchWnd(HWND hWnd) //在wndArray中查找hwnd是参数hWnd的TWin指针
{
for ( int cnt = 0; cnt < wndCnt; cnt++ )
{
if ( wndArray[cnt]->hWnd == hWnd )
{
return wndArray[cnt];
}
}
return NULL;
}
//找到TWin win指针的index
BOOL TApp::SearchWndIndex(TWin *win, int *index)
{
for ( *index = 0; *index < wndCnt; (*index) ++ )
{
if ( wndArray[*index] == win )
{
return TRUE;
}
}
return FALSE;
}
#if 0
IsXpManifest(void)
{
static BOOL done = FALSE;
static BOOL isXpManifest = FALSE;
//只查找一次,如果已经完成了查找,直接返回结果isXpManifest
if ( done )
{
return isXpManifest;
}
//是第一次判断
done = TRUE;
HMODULE hComctl;
char path[MAX_PATH];
if ( ( hComctl = ::GetModuleHandle("comctl32")) == NULL )
{
return isXpManifest = FALSE;
}
if ( ::GetModuleFileName(hComctl, path, sizeof(path)) == 0 )
{
return isXpManifest = FALSE;
}
GetFileVersionInfo();
VerQueryValue();
}
#endif
HINSTANCE LoadCtl3d(void)
{
if ( IsNewShell() )
{
return NULL;
}
HINSTANCE hCtl3d;
BOOL (WINAPI *Ctl3dRegister)(HANDLE);
BOOL (WINAPI *Ctl3dAutoSubclass)(HANDLE);
hCtl3d = ::LoadLibrary("ctl3d32.dll");
Ctl3dRegister = (BOOL (WINAPI *)(HANDLE))::GetProcAddress(hCtl3d, "Ctl3dRegister");
Ctl3dAutoSubclass = (BOOL (WINAPI *)(HANDLE))::GetProcAddress(hCtl3d, "Ctl3dAutoSubclass");
if ( Ctl3dRegister && Ctl3dAutoSubclass )
{
Ctl3dRegister(TApp::hI);
Ctl3dAutoSubclass(TApp::hI);
}
return hCtl3d;
}
其中TMsgApp的代码如下:
class TMsgApp : public TApp
{
public:
TMsgApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow);
virtual ~TMsgApp();
virtual void InitWindow(void);
};
实现文件如下:
static char *ipmsg_id =
"@(#)Copyright (C) H.Shirouzu 1996-2002 ipmsg.cpp Ver2.00";
#include <time.h>
#include "tlib.h"
#include "resource.h"
#include "ipmsg.h"
#define IPMSG_CLASS "ipmsg_class"
TMsgApp::TMsgApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow)
: TApp(_hI, _cmdLine, _nCmdShow)
{
//为后面的随机数做好准备
srand( (UINT)Time() );
}
TMsgApp::~TMsgApp()
{
}
void TMsgApp::InitWindow(void)
{
//注册一个窗口结构wc
WNDCLASS wc;
HWND hWnd;
char class_name[MAX_PATH] = IPMSG_CLASS, *tok, *msg, *p;
ULONG nicAddr = 0;
int port_no = atoi(cmdLine);
if ( port_no == 0 )//命令行中没有设置端口号,则设置为默认的端口号
{
//#define IPMSG_DEFAULT_PORT 0x0979
port_no = IPMSG_DEFAULT_PORT;
}
//解析命令行,由于这里没有命令行,所以这个if tok 里面的语句不会执行
if ( ( tok = strchr(cmdLine, '/')) && separate_token(tok, ' ', &p) )
{
BOOL diag = TRUE;
DWORD status = 0xffffffff;
if ( stricmp(tok, "/NIC") == 0 ) // NIC
{
if ( tok = separate_token(NULL, ' ', &p ) )
{
nicAddr = ResolveAddr(tok);
}
}
else if ( stricmp(tok, "/MSG") == 0 ) //
{
MsgMng msgMng(nicAddr, port_no);
ULONG command = IPMSG_SENDMSG|IPMSG_NOADDLISTOPT|IPMSG_NOLOGOPT, destAddr;
while ( ( tok = separate_token(NULL, ' ', &p ) ) != NULL && *tok == '/' )
{
if ( stricmp(tok, "/LOG") == 0 )
{
command &= ~IPMSG_NOLOGOPT;
}
else if ( stricmp(tok, "/SEAL") == 0 )
{
command |= IPMSG_SECRETOPT;
}
}
if ( ( msg = separate_token(NULL, 0, &p)) != NULL )
{
diag = FALSE;
if ( ( destAddr = ResolveAddr(tok)) != NULL )
{
status = msgMng.Send(destAddr, htons(port_no), command, msg) ? 0 : -1;
}
}
}
if ( nicAddr == 0 )
{
if ( diag )
{
MessageBox(0, "ipmsg.exe [portno] [/MSG [/LOG] [/SEAL] /
<hostname or IP addr> <message>]/r/nipmsg.exe [portno] /
[/NIC nic_addr]", MSG_STR, MB_OK);
}
::ExitProcess(status);
return;
}
}
//如果port_no不是默认的端口才这样做class_name=“ipmsg_class_0X979”
if ( port_no != IPMSG_DEFAULT_PORT || nicAddr )//这里端口已经设置好了,所以也不会执行
{
wsprintf(class_name, nicAddr ? "%s_%d_%s" : "%s_%d", IPMSG_CLASS,
port_no, inet_ntoa(*(in_addr *)&nicAddr) );
}
//建立WNDCLASS结构
memset( &wc, 0, sizeof(wc) );
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = TApp::WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hI;
wc.hIcon = ::LoadIcon(hI, (LPCSTR)IPMSG_ICON);
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = class_name;
HANDLE hMutex = ::CreateMutex( NULL, FALSE, class_name );
::WaitForSingleObject( hMutex, INFINITE );
//如果class_name名字的window已经存在了,则不创建新的程序,否则登记一下
//防止同时运行两个飞鸽!!
if ( ( hWnd = ::FindWindow( class_name, NULL ) ) != NULL
|| ::RegisterClass(&wc) == 0 )
{
if ( hWnd != NULL )//找到了飞鸽,把飞鸽设置为前台程序
{
::SetForegroundWindow(hWnd);
}
::ExitProcess(0xffffffff);
return;
}
//创建一个新的TMainWin窗口,这里的参数nicAddr为0,port_no为0X979
//这里创建各个管理类对象和常用到的各个窗口,创建udp socket 和tcpsocket
mainWnd = new TMainWin( nicAddr, port_no );
//创建TMainWin的CWnd窗口,启动时最小化
mainWnd->Create( class_name, IP_MSG, WS_OVERLAPPEDWINDOW |
( IsNewShell() ? WS_MINIMIZE : 0 ) );
//释放全局的hMutex变量
::ReleaseMutex(hMutex);
::CloseHandle(hMutex);
//InitApp完毕后进入Run函数里面的获得消息和派送消息了!
}