Ipmsg源码分析(二)

  Ipmsg.cpp为其主要的实现文件,其中调用系统的

int WINAPI WinMain(HINSTANCE hI, HINSTANCE, LPSTR cmdLine, int nCmdShow)作为入口函数,在函数中只是简单的调用了自己写的app类

TMsgApp app(hI, cmdLine, nCmdShow); // 调用其构造函数 创建对象

return app.Run(); // 由于TMsgApp没有自己的run

                                                // 因此会调用其父类TApp的Run                                            // 函数

 

在TMsgApp的构造函数的实现中,种下随机数字种子,只调用了一个系统函数

srand((UINT)Time());

 

TMsgApp 简单地public继承自TApp

在其继承中,添加了一个自己的函数virtual void InitWindow(void);

 

// 系统启动的时候调用的是其父类TApp的Run函数,此 函数如下。易知函数主要调用两个函数,随后进入消息循环。

 

  1. int TApp::Run(void)
  2. {
  3.     MSG     msg;
  4.     InitApp();                      // 实现注册窗口类, 设置窗口处理过程
  5.     InitWindow();                       // initWindow()在为一个纯虚函数,此处调用应该                                  // 是子类TMsgApp的initWindow()函数
  6.                                 // 注意:由于是子类调用的父类的run成员函数
  7.                                 // 而父类调用了一个纯虚函数,通过虚函数表,
  8.                                 // 此调用为调用子类的initWindow函数。
  9.     while (::GetMessage(&msg, NULL, 0, 0))
  10.     {
  11.         if (PreProcMsg(&msg))
  12.             continue;
  13.         ::TranslateMessage(&msg);
  14.         ::DispatchMessage(&msg);
  15.     }
  16.     return  msg.wParam;
  17. }

下面看子类实现的initWindow()主要完成了什么功能:

下面是子类TMsgApp的initWindow函数

 

  1. void TMsgApp::InitWindow(void)
  2. {
  3.     WNDCLASS    wc;
  4.     HWND        hWnd;
  5.     char        class_name[MAX_PATH] = IPMSG_CLASS, *tok, *msg, *p;
  6.     ULONG       nicAddr = 0;
  7.     int         port_no = atoi(cmdLine);
  8.     if (port_no == 0)           、、端口处理,是否设置了端口
  9.         port_no = IPMSG_DEFAULT_PORT;
  10.                         、、处理命令行消息,如果是命令行方式启动
  11.     if ((tok = strchr(cmdLine, '/')) && separate_token(tok, ' ', &p))
  12.     {
  13.         BOOL    diag = TRUE;
  14.         DWORD   status = 0xffffffff;
  15.         if (stricmp(tok, "/NIC") == 0)  
  16.         {
  17.             if (tok = separate_token(NULL, ' ', &p))
  18.                 nicAddr = ResolveAddr(tok);
  19.         }
  20.         else if (stricmp(tok, "/MSG") == 0) 
  21.         {
  22.             MsgMng  msgMng(nicAddr, port_no);
  23.             ULONG   command = IPMSG_SENDMSG|IPMSG_NOADDLISTOPT|IPMSG_NOLOGOPT, destAddr;
  24.             while ((tok = separate_token(NULL, ' ', &p)) != NULL && *tok == '/') {
  25.                 if (stricmp(tok, "/LOG") == 0)
  26.                     command &= ~IPMSG_NOLOGOPT;
  27.                 else if (stricmp(tok, "/SEAL") == 0)
  28.                     command |= IPMSG_SECRETOPT;
  29.             }
  30.             if ((msg = separate_token(NULL, 0, &p)) != NULL)
  31.             {
  32.                 diag = FALSE;
  33.                  if ((destAddr = ResolveAddr(tok)) != NULL)
  34.                     status = msgMng.Send(destAddr, htons(port_no), command, msg) ? 0 : -1;
  35.             }
  36.         }
  37. 、、显示出错信息,给用户以提示。此种错误仅仅在命令行方式下产生
  38.         if (nicAddr == 0)
  39.         {
  40.             if (diag)
  41.                 MessageBox(0, "ipmsg.exe [portno] [/MSG [/LOG] [/SEAL] <hostname or IP addr> <message>]/r/nipmsg.exe [portno] [/NIC nic_addr]", MSG_STR, MB_OK);
  42.             ::ExitProcess(status);
  43.             return;
  44.         }
  45.     }
  46.     if (port_no != IPMSG_DEFAULT_PORT || nicAddr)
  47.         wsprintf(class_name, nicAddr ? "%s_%d_%s" : "%s_%d", IPMSG_CLASS, port_no, inet_ntoa(*(in_addr *)&nicAddr));
  48.     memset(&wc, 0, sizeof(wc));
  49.     wc.style            = CS_DBLCLKS;
  50.     wc.lpfnWndProc      = TApp::WinProc;        、、窗口处理函数为一个静态成员函数
  51.     wc.cbClsExtra       = 0;
  52.     wc.cbWndExtra       = 0;
  53.     wc.hInstance        = hI;
  54.     wc.hIcon            = ::LoadIcon(hI, (LPCSTR)IPMSG_ICON);
  55.     wc.hCursor          = ::LoadCursor(NULL, IDC_ARROW);
  56.     wc.hbrBackground    = NULL;
  57.     wc.lpszMenuName     = NULL;
  58.     wc.lpszClassName    = class_name;
  59. // 创建互斥mutex来保护共享资源,但是由于创建此mutex的线程不拥有其使用权。// WaitForSingleObject函数什么时候返回呢?
  60.     HANDLE  hMutex = ::CreateMutex(NULL, FALSE, class_name);
  61.     ::WaitForSingleObject(hMutex, INFINITE);
  62.     if ((hWnd = ::FindWindow(class_name, NULL)) != NULL || ::RegisterClass(&wc) == 0)
  63.     {
  64.         if (hWnd != NULL)
  65.             ::SetForegroundWindow(hWnd);
  66.         ::ExitProcess(0xffffffff);
  67.         return;
  68.     }
  69.                              // 生成主窗口,并且将其显示
  70.     mainWnd = new TMainWin(nicAddr, port_no);
  71.     mainWnd->Create(class_name, IP_MSG, WS_OVERLAPPEDWINDOW | (IsNewShell() ? WS_MINIMIZE : 0));
  72.     ::ReleaseMutex(hMutex);
  73.     ::CloseHandle(hMutex);
  74. }

 

主程序的窗口处理过程为TApp类的一个静态成员函数,由此可知。回调函数可以封装在类中,但是注意必须作为类的静态成员函数。

 

 

  1. LRESULT CALLBACK TApp::WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2. {
  3.     TWin *win = SearchWnd(hWnd);
  4.     
  5. // 调用子类的窗口处理函数 由于其父类窗口处理过程定义的都为虚函数,而且基本没有对// 消息进行处理,因此主要在子类中实现消息处理过程,这就是调用虚函数的好处
  6.     if (win)
  7.         return  win->WinProc(uMsg, wParam, lParam); 
  8.                                             
  9.     
  10.     if ((win = preWnd) != NULL)
  11.     {
  12.         preWnd = NULL;
  13.         AddWinByWnd(win, hWnd);
  14.         return  win->WinProc(uMsg, wParam, lParam);
  15.     }
  16.     
  17.     return  DefWindowProc(hWnd, uMsg, wParam, lParam);
  18. }

 

此程序将创建的所有的窗口句柄放到一个句柄数组中,以便查询。此窗口数组是TWin的静态数据成员。此静态成员变量操作了静态成员函数

 

如果找到了接受消息的窗口句柄,调用窗口句柄的消息处理函数进行处理

LRESULT TWin::WinProc(UINT uMsg, WPARAM wParam, LPARAM lParam)

此窗口处理过程处理以下消息:

WM_CREATE、WM_CLOSE、WM_COMMAND、WM_SYSCOMMAND、WM_TIMER、WM_NCDESTROY、WM_QUERYENDSESSION、WM_ENDSESSION、WM_QUERYOPENWM_PAINT、WM_NCPAINT、WM_SIZE、WM_GETMINMAXINFO、WM_SETCURSOR、WM_MOUSEMOVE、WM_NCHITTEST、

WM_MEASUREITEM、WM_DRAWITEM、WM_NOTIFY、WM_CONTEXTMENU、WM_HOTKEY、WM_VSCROLL

 

此语句作用:如果done为真,即消息已经被处理,返回result,否则调用默认消息处理函数。

return done ? result : DefWindowProc(uMsgwParamlParam);

下面主要完成对TMainWin类中函数的分析,此函数中完成发送到此窗口的消息的处理。         

例如TWin中成员函数WinProc调用了函数EvCreate();

由于在父类和子类中都存在EvCreate()函数。用基类的指针调用函数的时候,基类指针得到对象类型的确定化。调用父类中的WinProc函数(子类中没有对此函数进行重载),在WinProc函数中调用EvCreate(),此时应该调用子类的EvCreate()函数。可以理解为在调用函数的时候始终存在this指针,根据this指针指向的类型和类型中的成员函数是否是虚函数,是否重新定义来确定到底调用哪一个函数。

分析EvTimer函数处理过程。

此函数处理定时器消息。根据TimeID的不同分别进行处理

取得在线列表,是udp方式发送一个广播,此局域网中所有用户都可以接受到此消息,由于此消息有特定的格式,标识符等信息,由于是对特定端口进行的广播,故此局域网是哪个的所有用户都可以接受到此消息。

未完待续。。。

posted @ 2012-09-20 10:54  zearin  阅读(589)  评论(0编辑  收藏  举报