IPMsg
来源:互联网 发布:广州万户网络怎么样 编辑:程序博客网 时间:2024/05/21 17:00
简单介绍:
IP Messenger : http://ipmsg.org (p.s.:该网站的右上角有英文版网页链接)
岛国H.Shirouzu写的跨平台局域网通信开源软件,基于TCP/IP,不需要服务器。
国内大家用的Feiq(飞秋)就是作者基于IPMsg写的,目前更新到r3.42。
初学tcp/ip的盆友不妨把source code抓下来读一读,ipmsg自己定义了一套应用层协议,消息的收发基于udp协议,文件的收发基于tcp。
我记得学校里最初学tcp/ip时,教的是c/s模型的socket编程,先写个server在那儿一直while(1),这边再启动几个client,如此,一个简单的局域网通信软件就写好了。
ipmsg source code里面有对ipmsg protocol作说明,基于日文有其它程序员翻译成了英文的prot-eng.txt。 如,启动或退出时通过向(255.255.255.255)广播的方式把消息发出去。
话说此文不会针对IPMsg协议来写,主要还是Win32流程的东西。上一稿《Win32 application (1) Begin》,讲到vs创建win32 app后,就没有下文了,今天接着写我的。关于Win32应用的流程介绍蜘蛛网上有很多高质量的网文,请大家自行使用搜索引擎。
关于ipmsg的source code的话,有几点需要说明:
1.作者貌似是用vs2005写的,我把代码资源些都放到vs2012面,直接是编不过的,至于怎么解决,我也不知道,有谁知道的话不妨留言分享一下,thanks。
2.Source code里面的很多注释都是日文写的,我用VS2012没有乱码出现,如果你用Source Insight或其它,可能需要再配置一下字体什么的,让它支持日文显示。
3.external:
使用了libpng & zlib.
4. src:
install是面的source code及resource file都是用于安装ipmsg时的GUI显示及逻辑处理;
uninst则反之;
TLib则是ipmsg软件的主要基类:
用VS查看类图:
1)TApp
2) TWin
按照实现Win32 applicaiton的流程来看ipmsg中Win32部分的流程:
1. WinMain入口
2. Registers the window class. --> 注册需要挂一个callback function(To processes messages for the main window.)
3. Application initialization: saves instance handle and creates main window
4. Main message loop
ipmsg.cpp最后定义了WinMain:
int WINAPI WinMain(HINSTANCE hI, HINSTANCE, LPSTR cmdLine, int nCmdShow){if (IsWin95()) {MessageBox(0, "Please use old version (v2.06 or earlier)","Win95/98/Me is not supported", MB_OK);::ExitProcess(0xffffffff);return0;}TMsgAppapp(hI, cmdLine, nCmdShow);returnapp.Run();}定义了一个TMsgApp类的对象,从前面的类图知道TMsgApp是从TApp继承过来的。TMsgApp没有重新定义Run(),所以多态地直接调用父类的Run():
int TApp::Run(void){MSGmsg;InitApp();InitWindow();while (::GetMessage(&msg, NULL, 0, 0)){if (PreProcMsg(&msg))continue;::TranslateMessage(&msg);::DispatchMessage(&msg);}return(int)msg.wParam;}现在可以看出,Run()和我们用VS直接自动生成的WinMain函数:
1) InitApp注册窗口类;
2) InitWindow实例化窗口;
3) 最后消息处理循环。
1) InitApp注册窗口类,并挂载WinProc处理Window Message
BOOL TApp::InitApp(void)// reference kwc{WNDCLASSW 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= (LPCWSTR)defaultClassV;if (::FindWindowV(defaultClassV, NULL) == NULL){if (::RegisterClassV(&wc) == 0)return FALSE;}returnTRUE;}TApp类实现的WinProc():
LRESULT CALLBACK TApp::WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){TApp*app = TApp::GetApp();TWin*win = app->SearchWnd(hWnd);if (win)returnwin->WinProc(uMsg, wParam, lParam);if ((win = app->preWnd)){app->preWnd = NULL;app->AddWinByWnd(win, hWnd);returnwin->WinProc(uMsg, wParam, lParam);}return::DefWindowProc(hWnd, uMsg, wParam, lParam);}可以看出,TApp作为父类,通过传递进来的窗口HANDLE找到对应的Window,并调用Window的消息处理函数。
这里会调用到TWin类的WinProc():
LRESULT TWin::WinProc(UINT uMsg, WPARAM wParam, LPARAM lParam){BOOLdone = FALSE;LRESULTresult = 0;switch(uMsg){case WM_CREATE:GetWindowRect(&orgRect);done = EvCreate(lParam);break;case WM_CLOSE:done = EvClose();break;case WM_COMMAND:done = EvCommand(HIWORD(wParam), LOWORD(wParam), lParam);break;case WM_SYSCOMMAND:done = EvSysCommand(wParam, MAKEPOINTS(lParam));break;case WM_TIMER:done = EvTimer(wParam, (TIMERPROC)lParam);break;case WM_DESTROY:done = EvDestroy();break;/* other case */}
TWin作为主窗口类,ipmsg从TWin继承了很多的子类,TMainWin是其中一个。
2) InitWindow实例化窗口TApp将InitWindow()声明为virtual,需要子类来实现,下面是
TMsgApp类实现的InitWindow():
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; /* ... ... something ... ... */ 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);}
从后面可以看到mainWnd被实例化为一个TMainWin类的对象,并调用TMainWin类的create函数来创建main window;继续跟下去会发现它最终调用到了TWin的CreateV():
BOOL TWin::CreateV(const void *className, const void *title, DWORD style, DWORD exStyle, HMENU hMenu){ if (className == NULL) { className = TApp::GetApp()->GetDefaultClassV(); } TApp::GetApp()->AddWin(this); if ((hWnd = ::CreateWindowExV(exStyle, className, title, style, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parent ? parent->hWnd : NULL, hMenu, TApp::GetInstance(), NULL)) == NULL) return TApp::GetApp()->DelWin(this), FALSE; else return TRUE;}
reateWindowExV()被不是Windows SDK提供的API,而只是TLib里定义的一个函数指针:
HWND (WINAPI *CreateWindowExV)(DWORD exStyle, const void *className, const void *title, DWORD style, int x, int y, int nw, int nh, HWND hParent, HMENU hMenu, HINSTANCE hI, void *param);
如果是在Windows系统中跑,它最终会指向CreateWindowExW这个Windows API。
至此,实例化窗口顺序调用就完成了,不过并没有看到主窗口是怎么设计的,它只不过创建了一个窗口,仅此而已,并且,没有看到Show&Update。当然这是在WinProc里收到WM_CREATE里面来做的,主窗口的EvCreate:
LRESULT TWin::WinProc(UINT uMsg, WPARAM wParam, LPARAM lParam){ BOOL done = FALSE; LRESULT result = 0; switch(uMsg) { case WM_CREATE: GetWindowRect(&orgRect); done = EvCreate(lParam); break; /* other case */ }}
从TWin类继承来的TMainWin重新定义了WinProc函数:
BOOL TMainWin::EvCreate(LPARAM lParam){ hMainWnd = hWnd; mainWin = this; if (IsWinVista() && TIsUserAnAdmin() && TIsEnableUAC()) { TChangeWindowMessageFilter(WM_DROPFILES, 1); TChangeWindowMessageFilter(WM_COPYDATA, 1); TChangeWindowMessageFilter(WM_COPYGLOBALDATA, 1); TChangeWindowMessageFilter(WM_CLOSE, 1); } if (!msgMng->GetStatus()) return TRUE; if (cfg->TaskbarUI) { Show(SW_MINIMIZE); } else { Show(SW_HIDE); } while (!TaskTray(NIM_ADD, hMainIcon, IP_MSG)) { Sleep(1000); // for logon script } TaskBarCreateMsg = ::RegisterWindowMessage("TaskbarCreated"); TaskBarButtonMsg = ::RegisterWindowMessage("TaskbarButtonCreated"); TaskBarNotifyMsg = ::RegisterWindowMessage(IP_MSG); SetIcon(cfg->AbsenceCheck ? hRevIcon : hMainIcon); SetCaption(); if (!SetupCryptAPI(cfg, msgMng)) MessageBoxU8("CryptoAPI can't be used. Setup New version IE"); msgMng->AsyncSelectRegister(hWnd); SetHotKey(cfg); if (msgMng->GetStatus()) { EntryHost(); } if (IsWin7()) { // for TaskbarUI ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (cfg->TaskbarUI) { CreateJumpList(className); } else {// DeleteJumpList(); } } ::SetTimer(hWnd, IPMSG_CLEANUP_TIMER, 60000, NULL); // 1min return TRUE;}
Show Window: Show(SW_HIDE); 调用Windows API。IPMsg启动后会自动最小化,所以你不会看到有一个主窗口界面出现,不过它的确已经创建了一个main window,当然尝试点击右下角的图标来打开IPMsg时,会触发BUTTON事件,WinProc会去处理WM_LBUTTONUP消息, 用来Send Msg的窗口就会打开。
void TWin::Show(int mode){ ::ShowWindow(hWnd, mode); ::UpdateWindow(hWnd);}
3) 最后消息处理循环
while (::GetMessage(&msg, NULL, 0, 0)) { if (PreProcMsg(&msg)) continue; ::TranslateMessage(&msg); ::DispatchMessage(&msg); }
其中,PreProcMsg()是为了将msg传递给对应的窗口去处理,自己的娃自己管好,你不管,就要交给父辈来管。最后最后,就是编写各种消息处理函数了,当然Win32主流程当中也有不少细节在这里没有说,大家不妨自己抓份source code来读一读。上一个post中提到Win32 application开发,各种蛋疼,其中一个原因就是Win32没有像WinForm或WPF那样可以直接拖动控件来布局应用的图形界面,其实Win32是有的,Windows SDK已经提供了一些基本的控件给Win32开发人员。
用这些控件前需要调用 InitCommonControls()或者InitCommonControlsEx()来初始化一下,这个函数在Commctrl.h里声明的。
这是IPMsg用来发消息的Dialog窗口,当然啰,要做出Tencent QQ那样的漂亮界面,还需要自己去定制一些界面库来实现。
- Ipmsg
- IPMsg
- IPmsg 编译
- IPMSG从头开始
- java调用ipmsg源代码
- PHP下调用IPMSG
- Fedora 7 安装ipmsg
- IPMSG(飞鸽传书)协议翻译
- IPMSG(飞鸽传书)协议翻译
- IPMSG(飞鸽传书)协议翻译
- F10 intall ipmsg
- ipmsg飞鸽传书系统即时通讯
- 飞鸽传书管理软件-“ipmsg”
- ipmsg 文件传输协议
- ubuntu下安装IPMSG
- 从编译ipmsg开始
- 命令行发送IpMsg
- linux-IPMSG安装步骤
- GCC 使用详解
- 程序员面试常见面试题之数据库知识篇
- Vi 编辑器的基本使用方法
- 【文摘】ABC(Always Be Coding)
- Linux bootloader 编写方法
- IPMsg
- faac 移植到android
- 【3.3 竖式问题】
- 使用 P3P 规范让 IE 跨域接受第三方 cookie
- Linux 下C语言编程基础
- 10个开源的PHP网站内容管理系统
- 深入剖析 uClinux
- Linux 学习指导
- DRUID数据库链接池