TMsgApp类声明如下:
//ipmsgcmn.h/line1713
class TMsgApp : public TApp {
public:
TMsgApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow);
virtual ~TMsgApp();
virtual void InitWindow(void);
};
(一)继承关系
1. TMsgApp类继承自TApp类
(二)构造函数
1. TMsgApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow)
//ipmsg.cpp/line19
TMsgApp::TMsgApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow) : TApp(_hI, _cmdLine, _nCmdShow)
{
LoadLibrary("RICHED20.DLL");
srand((UINT)Time());
TLibInit_AdvAPI32();
TLibInit_Crypt32();
TLibInit_WinSock();
}
调用父类的构造函数,然后做3件事:
(1) 加载库RICHED20.DLL,这个动态链接库的作用是字符编辑器相关文件。LoadLibrary()函数的作用是载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源。
(2) 以当前时间作为随机数的种子。
(3) 首先介绍一下三个模块:
advapi32.dll:advapi32.dll是一个高级API应用程序接口服务库的一部分,包含的函数与对象的安全性,注册表的操控以及事件日志。
crypt32.dll:是windows加密API应用程序接口模块.
Ws2_32.dll: windows socket编程相关的模块
程序将这三个模块中的库函数取出来,并初始化IPMsg项目自己的函数指针。
2. ~TMsgApp()
TMsgApp::~TMsgApp()
{
}
由此可见析构函数在本类中不做任何的事情,析构的过程要利用父类的析构函数来完成。
(二)成员变量
无
(三)成员函数
1. void TMsgApp::InitWindow(void)
//ipmsg.cpp/line32
void TMsgApp::InitWindow(void)
{
HWND hWnd;
char class_name[MAX_PATH_U8] = IPMSG_CLASS, *tok, *msg, *p;
char *class_ptr = NULL;
ULONG nicAddr = 0;
int port_no = atoi(cmdLine);
BOOL show_history = FALSE;
enum Stat { ST_NORMAL, ST_TASKBARUI_MSG, ST_EXIT, ST_ERR } status = ST_NORMAL;
int taskbar_msg = 0;
int taskbar_cmd = 0;
if (port_no == 0) port_no = IPMSG_DEFAULT_PORT;
if ((tok = strchr(cmdLine, '/'))) {
DWORD exit_status = 0xffffffff;
for (tok=separate_token(tok, ' ', &p); tok && *tok == '/';
tok=separate_token(NULL, ' ', &p)) {
if (stricmp(tok, "/NICLIST") == 0) {
int num = 0;
AddrInfo *addrs = GetIPAddrs(FALSE, &num);
char buf[8192] = "No NIC", *p = buf;
for (int i=0; addrs && i < num; i++) {
p += sprintf(p, " NIC(%d) = %s\n", i+1, Tinet_ntoa(*(LPIN_ADDR)&addrs[i].addr));
}
MessageBox(0, buf, IP_MSG, MB_OK);
delete [] addrs;
status = ST_EXIT;
}
else if (stricmp(tok, "/NICID") == 0) { // NICID 指定
status = ST_ERR;
if ((tok = separate_token(NULL, ' ', &p))) {
int target = atoi(tok) - 1;
int num = 0;
AddrInfo *addrs = GetIPAddrs(FALSE, &num);
if (addrs && target > 0 && target < num) {
nicAddr = addrs[target].addr;
status = ST_NORMAL;
}
delete [] addrs;
}
if (status == ST_ERR) break;
}
else if (stricmp(tok, "/NIC") == 0) { // NIC 指定
if (!(tok = separate_token(NULL, ' ', &p)) || !(nicAddr = ResolveAddr(tok))) {
status = ST_ERR;
break;
}
}
else if (stricmp(tok, "/MSG") == 0) { // コマンドラインモード
MsgMng msgMng(nicAddr, port_no);
ULONG command = IPMSG_SENDMSG|IPMSG_NOADDLISTOPT|IPMSG_NOLOGOPT, destAddr;
status = ST_EXIT;
while ((tok = separate_token(NULL, ' ', &p)) && *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)) && (destAddr = ResolveAddr(tok))) {
exit_status = msgMng.Send(destAddr, Thtons(port_no), command, msg) ? 0 : -1;
}
else status = ST_ERR;
}
else if (stricmp(tok, "/SHOW_HISTORY") == 0) { // インストーラからの起動
show_history = TRUE;
}
else if (stricmp(tok, "/TASKBAR_MSG") == 0) { // TaskbarUI用
if (!(class_ptr = separate_token(NULL, ' ', &p))
|| !(tok = separate_token(NULL, ' ', &p))
|| !(taskbar_cmd = atoi(tok))
|| !(taskbar_msg = ::RegisterWindowMessage(IP_MSG))) {
status = ST_ERR;
break;
}
if ((hWnd = FindWindowU8(class_ptr))) {
::PostMessage(hWnd, taskbar_msg, taskbar_cmd, 0);
}
::ExitProcess(0xffffffff);
return;
}
else status = ST_ERR;
}
if (status != ST_NORMAL) {
if (status == ST_ERR) {
MessageBox(0, IPMSG_USAGE, IP_MSG, MB_OK);
}
::ExitProcess(exit_status);
return;
}
}
if (port_no != IPMSG_DEFAULT_PORT || nicAddr) {
wsprintf(class_name, nicAddr ? "%s_%d_%s" : "%s_%d",
IPMSG_CLASS, port_no, Tinet_ntoa(*(in_addr *)&nicAddr));
}
HANDLE hMutex = ::CreateMutex(NULL, FALSE, class_name);
::WaitForSingleObject(hMutex, INFINITE);
if ((hWnd = FindWindowU8(class_name)) ||
!TRegisterClassU8(class_name, CS_DBLCLKS, ::LoadIcon(hI, (LPCSTR)IPMSG_ICON),
::LoadCursor(NULL, IDC_ARROW))) {
if (hWnd) ::SetForegroundWindow(hWnd);
::ExitProcess(0xffffffff);
return;
}
mainWnd = new TMainWin(nicAddr, port_no);
mainWnd->Create(class_name);
::ReleaseMutex(hMutex);
::CloseHandle(hMutex);
if (show_history) mainWnd->SendMessage(WM_COMMAND, MENU_HELP_HISTORY, 0);
}
(1)定义HWND类型局部变量hWnd;
(2)定义char*类型局部变量class_name,tok,msg,p,class_ptr。初始化class_name为数组大小为MAX_PATH_U8 ,大小参看下面的代码段,内容为IPMSG_CLASS,参看下面的字符串。初始化class_ptr为空指针。
//tlib.h/line106
#define MAX_PATH_U8 (MAX_PATH * 3)
//minwindef.h/line60
//定义了编译器所支持的最长全路径名的长度
#define MAX_PATH 260
//ipmsg.cpp/line16
#define IPMSG_CLASS "ipmsg_class"
(3)初始化ULONG类型的nicaddr为0,表示的是IP地址的长整形值。
(4)根据父类的cmdLine值初始化int类型局部变量prot_no参数。这个值表示端口。
(5)定义变量show_history为FALSE;
(6)定义枚举类型变量status并初始化为ST_NORMAL,即0;
(7)定义并初始化int类型的taskbar_msg,taskbar_cmd为0;
(8)如果port_no从cmdline中没有取到值,那么就初始化为默认值 IPMSG_DEFAULT_PORT;
//ipmsg.h/line21
#define IPMSG_DEFAULT_PORT 0x0979
(9)如果cmdline变量中不包含任何的命令,即‘/’那么按照如下流程运行:
9.1 利用CreateMutex()函数创建互斥体,然后调用WaitForSingleObject()阻塞其他进程进入该互斥体,即系统中只能同时有一个进程进入该互斥体中运行。
9.2 查看是否有窗口类名为class_name的窗口正在运行,如果有的话hWnd的值为该窗口的句柄,否则的话为NULL 。
hWnd不为空,那么调用SetForegroundWindow函数将该函数将hWnd窗口的线程设置到前台,并且激活该窗口。然后从InitWindow函数退出,无返回值。
如果hWnd为空,那么就以class_name为窗口类名注册一个窗口,如果注册失败了就从InitWindow函数退出,无返回值。如果注册成功了,就接着运行9.3
9.3 定义一个TMainWin对象并且用父类的mainWnd指针成语指向它。
9.4 调用mainWnd指针指向对象的Create()函数。
9.5 释放互斥区
9.6 关闭句柄
9.7 如果show_history为真,那么就调用mainWnd指针指向TWin对象的sendMessage()函数。
9.8 InitWindow9()函数运行完毕。
10.如果在CmdLine中含有命令
这部分以后再分析,因为当前分析的是直接双击启动,而不是从命令行启动,所以cmdline都是空的。