CRTCWin
这个类是主窗口所在,在这里按照我们的经验,首先应该提供注册窗口类的函数,然后应该定义窗口过程。而事实上也确实是这样的,这两个函数都是静态函数。
对于注册窗口类的函数,基本上是一个标准的过程,唯一需要注意的就是窗口过程是一个C++静态函数,对于C++来说,普通的成员函数是不能作为这样的函数指针的,这一点可以参考STANLEY B.LIPPMAN,JOSEE LAJOIE的《C++ Primer》一书。
RegisterClass函数
WNDCLASS wc;
ATOM atom;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)CRTCWin::WindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_APP);
wc.lpszClassName = APP_CLASS;
atom = ::RegisterClass( &wc );
而对于窗口过程处理函数来说,也基本上是一个标准的过程,在这里只处理这样几个消息:WM_CREATE,WM_DESTROY,WM_CLOSE,WM_SIZE,WM_COMMAND,WM_NOTIFY,WM_RTC_EVENT。而WM_RTC_EVENT消息是自定义的消息,在这里处理各种RTC相关的消息。
WindowProc函数
CRTCWin * me = NULL;
LRESULT lr = 0;
if ( uMsg == WM_CREATE )
{
// Create an instance of the class
me = new CRTCWin;
if(!me)
{
// Failed to create the instance
return -1;
}
me->m_hWnd = hWnd;
// Store the class instance pointer in the
// window's user data for later retrieval
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)me);
lr = me->OnCreate(uMsg, wParam, lParam);
}
else
{
// Retrieve the class instance pointer from the
// window's user data
me = (CRTCWin *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch( uMsg )
{
case WM_DESTROY:
lr = me->OnDestroy(uMsg, wParam, lParam);
// Delete the object instance
delete me;
// Quit the application
PostQuitMessage(0);
break;
case WM_CLOSE:
lr = me->OnClose(uMsg, wParam, lParam);
break;
case WM_SIZE:
lr = me->OnSize(uMsg, wParam, lParam);
break;
case WM_COMMAND:
lr = me->OnCommand(uMsg, wParam, lParam);
break;
case WM_NOTIFY:
lr = me->OnNotify(uMsg, wParam, lParam);
break;
case WM_RTC_EVENT:
lr = me->OnRTCEvent(uMsg, wParam, lParam);
break;
default:
lr = DefWindowProc( hWnd, uMsg, wParam, lParam );
}
}
return lr;
在这里应该注意Windows SDK编程常用的一个技巧,就是把一些用户数据存储在窗口信息中,也就是SetWindowLongPtr()函数的使用。
OnCreate
这个函数负责窗口的创建过程中的初始化,在创建窗口的时候会调用这个函数。这个函数要完成各种初始化,它完成了下面一些工作:
(1) 创建窗口界面相关的元素。
创建状态条
m_hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE,
NULL,
m_hWnd,
IDC_STATUSBAR);
创建树形控件,同时进行初始化,创建了两个根一级的目录:online和offline。这两个目录的信息都被保存了下来(m_hOnlineParent和m_hOfflineParent)。
m_hBuddyTree = CreateWindowExW(WS_EX_CLIENTEDGE,
L"SysTreeView32",
NULL,
WS_CHILD | WS_VISIBLE |
TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS,
0, 0,
0, 0,
m_hWnd,
(HMENU)IDC_BUDDYTREE,
GetModuleHandle(NULL),
NULL);
TV_ITEM tviNewItem;
ZeroMemory(&tviNewItem, sizeof(TV_ITEM));
tviNewItem.mask = TVIF_TEXT;
tviNewItem.pszText = L"Online";
TVINSERTSTRUCT tvis;
ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT));
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_ROOT;
tvis.item = tviNewItem;
HTREEITEM hti = TreeView_InsertItem(m_hBuddyTree, &tvis);
ZeroMemory(&tviNewItem, sizeof(TV_ITEM));
tviNewItem.mask = TVIF_TEXT;
tviNewItem.pszText = L"Offline";
ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT));
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_ROOT;
tvis.item = tviNewItem;
hti = TreeView_InsertItem(m_hBuddyTree, &tvis);
(2) 初始化RTC Client。
在这里,需要创建RTC Client,设置网络协议,端口,然后设置回答-侦听的模式(PC-PC,IM,PC-Phone,Phone-Phone等),还有一件必须要做的事情就是设置事件的过滤标记。
//创建RTC Client
HRESULT hr;
hr = CoCreateInstance(__uuidof(RTCClient),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IRTCClient2),
(LPVOID *)&m_pClient
);
//检查版本号
long lVersion;
hr = m_pClient->get_Version(&lVersion);
if (lVersion < 0x00010002)
{
return -1;
}
// 初始化RTC client
hr = m_pClient->Initialize();
// 设置事件过滤标记,这一步是必须的
long lFlags = RTCEF_REGISTRATION_STATE_CHANGE |
RTCEF_SESSION_STATE_CHANGE |
RTCEF_PARTICIPANT_STATE_CHANGE |
RTCEF_MESSAGING |
RTCEF_MEDIA |
RTCEF_INTENSITY |
RTCEF_CLIENT |
RTCEF_BUDDY |
RTCEF_BUDDY2 |
RTCEF_WATCHER |
RTCEF_WATCHER2 |
RTCEF_GROUP |
RTCEF_USERSEARCH |
RTCEF_ROAMING |
RTCEF_PROFILE |
RTCEF_PRESENCE_PROPERTY |
RTCEF_PRESENCE_DATA |
RTCE_MEDIA_REQUEST;
hr = m_pClient->put_EventFilter(lFlags);
// 设置RTC Client的侦听模式:设置端口
// RTCLM_BOTH opens the standard SIP port 5060, as well as a dynamic port.
hr = m_pClient->put_AllowedPorts(RTCTR_TCP, RTCLM_BOTH);
hr = m_pClient->put_AllowedPorts(RTCTR_UDP, RTCLM_BOTH);
// 回答模式
hr = m_pClient->put_AnswerMode(RTCST_PC_TO_PC, RTCAM_OFFER_SESSION_EVENT);
hr = m_pClient->put_AnswerMode(RTCST_IM, RTCAM_AUTOMATICALLY_ACCEPT);
hr = m_pClient->put_AnswerMode(RTCST_MULTIPARTY_IM, RTCAM_AUTOMATICALLY_ACCEPT);
hr = m_pClient->put_AnswerMode(RTCST_APPLICATION, RTCAM_OFFER_SESSION_EVENT);
hr = m_pClient->put_AnswerMode(RTCST_PC_TO_PHONE, RTCAM_AUTOMATICALLY_REJECT);
hr = m_pClient->put_AnswerMode(RTCST_PHONE_TO_PHONE, RTCAM_AUTOMATICALLY_REJECT);
// 创建事件接收对象:这是一个COM组件
m_pEvents = new CRTCEvents;
hr = m_pEvents->Advise( m_pClient, m_hWnd );
// 注册RTC Client
BSTR bstr = ::SysAllocString(L"RTCSample_Test_Version");
hr = m_pClient->put_ClientName( bstr);
::SysFreeString(bstr);
WCHAR p[128];
swprintf(p,L"Built:%S.%S", __DATE__,__TIME__);
bstr = ::SysAllocString(p);
hr = m_pClient->put_ClientCurVer( bstr);
::SysFreeString(bstr);
// 初始化参与者信息:主要是填充前面创建的树形控件的数据,这个函数在后面分析
DoSetPresence(RTCXS_PRESENCE_ONLINE);
(3) 程序启动
程序在启动的时候就会提示用户进行登录。
PostMessage(m_hWnd, WM_COMMAND, MAKEWPARAM(ID_FILE_LOGON, 0), 0);
OnDestroy
在这里完成资源的释放操作。
// Release the RTC profile
SAFE_RELEASE(m_pProfile);
// Cleanup the buddy list
ClearBuddyList();
if (m_pClient)
{
if (m_pEvents)
{
// Unadvise for events from the RTC client
m_pEvents->Unadvise(m_pClient);
m_pEvents = NULL;
}
// Shutdown the RTC client
m_pClient->Shutdown();
// Release the RTC client
SAFE_RELEASE(m_pClient);
}
对于m_pClient和m_pEvents来说和OnCreate存在对应关系,比较容易理解。而对于m_pProfile和Buddy来说,其实是在其他地方创建的。
OnClose
关闭会话,准备关闭RTC Client。
HRESULT hr = S_OK;
DEBUG_PRINT(("WINDOW CLOSED"));
// Cleanup the existing session windows
CleanupSessions();
// Cleanup the user search windows
CleanupUserSearches();
// Cleanup the watcher windows
CleanupWatchers();
////////////
//
// Begin RTC Functionality Code
//
// This code demonstrates how to prepare the client for shutdown.
// This should be called before the Shutdown method on the client.
//
////////////
if (m_pClient)
{
// Prepare the RTC client object for shutdown
hr = m_pClient->PrepareForShutdown();
}
if (!m_pClient || FAILED(hr))
{
// The RTC client object either doesn't exist, or
// failed to prepare for shutdown. Destroy the
// window now
DestroyWindow(m_hWnd);
}
else
{
// The RTC client object is preparing to shutdown.
// We should wait for the RTCCET_ASYNC_CLEANUP_DONE
// event before we shutdown the RTC client. For now
// just hide the window
ShowWindow(m_hWnd, SW_HIDE);
}
OnSize
当整个窗口大小发生变化的时候,控件也应该跟着发生变化。这一点对于程序来说属于细枝末节,这里不需要详细讨论(无非获取窗口大小,重新计算)。
OnCommand
在这里处理菜单工具栏之类的消息。这里的具体实现同样是在其他函数中完成,所以这个地方不需要详细了解。
HRESULT hr;
switch(LOWORD(wParam))
{
case ID_FILE_LOGON: //登录:需要获取相关的登录信息
{
BSTR bstrURI = NULL;
BSTR bstrServer = NULL;
BSTR bstrTransport = NULL;
hr = ShowLogonDialog(m_hWnd, &bstrURI, &bstrServer, &bstrTransport);
DoLogOn(bstrURI, bstrServer, bstrTransport);
SAFE_FREE_STRING(bstrURI);
SAFE_FREE_STRING(bstrServer);
SAFE_FREE_STRING(bstrTransport);
}
break;
case ID_FILE_LOGOFF: //注销登录
DoLogOff();
break;
case ID_FILE_EXIT: //程序退出
PostMessage(m_hWnd, WM_CLOSE, 0, 0);
break;
case ID_ACTION_ADDBUDDY: //增加网友
{
BSTR bstrURI = NULL;
BSTR bstrName = NULL;
// Show the add buddy dialog
hr = ShowAddressDialog(m_hWnd, L"Add Buddy", &bstrURI, &bstrName);
// Add the buddy
DoAddBuddy(bstrURI, bstrName);
SAFE_FREE_STRING(bstrURI);
SAFE_FREE_STRING(bstrName);
}
break;
case ID_ACTION_CALL: //呼叫
{
BSTR bstrURI = NULL;
// Show the call dialog
hr = ShowAddressDialog(m_hWnd, L"Call To", &bstrURI, NULL);
// Call the user
DoCall(RTCST_PC_TO_PC, bstrURI, NULL);
SAFE_FREE_STRING(bstrURI);
}
break;
case ID_ACTION_MESSAGE: //消息
{
BSTR bstrURI = NULL;
// Show the call dialog
hr = ShowAddressDialog(m_hWnd, L"Message To", &bstrURI, NULL);
// Send a message to the user
DoCall(RTCST_MULTIPARTY_IM, bstrURI, NULL);
SAFE_FREE_STRING(bstrURI);
}
break;
case ID_TOOLS_TUNINGWIZARD: //调音
DoTuningWizard();
break;
case ID_TOOLS_USERSEARCH: //用户搜索
AddUserSearch();
break;
case ID_TOOLS_WATCHERS: //监测
AddWatchers();
break;
case ID_TOOLS_GROUPS: //群组
AddGroups();
break;
case ID_TOOLS_OPTIONS: //选项,设置参数信息
DoOptions();
break;
case ID_TOOLS_DTMFDIALPAD: //
DoDTMFDialpad();
break;
case ID_FILE_PRESENCESTATUS_OFFLINE: //参与者状态之离线
DoSetPresence(RTCXS_PRESENCE_OFFLINE);
break;
case ID_FILE_PRESENCESTATUS_ONLINE: //参与者状态之在线
DoSetPresence(RTCXS_PRESENCE_ONLINE);
break;
case ID_FILE_PRESENCESTATUS_AWAY: //参与者状态之离去
DoSetPresence(RTCXS_PRESENCE_AWAY);
break;
case ID_FILE_PRESENCESTATUS_IDLE: //参与者状态之空闲
DoSetPresence(RTCXS_PRESENCE_IDLE);
break;
case ID_FILE_PRESENCESTATUS_BUSY: //参与者状态之忙碌
DoSetPresence(RTCXS_PRESENCE_BUSY);
break;
case ID_FILE_PRESENCESTATUS_BERIGHTBACK: //参与者状态之恢复正常
DoSetPresence(RTCXS_PRESENCE_BE_RIGHT_BACK);
break;
case ID_FILE_PRESENCESTATUS_ONTHEPHONE: //参与者状态之接听电话
DoSetPresence(RTCXS_PRESENCE_ON_THE_PHONE);
break;
case ID_FILE_PRESENCESTATUS_OUTTOLUNCH: //参与者状态之外出就餐
DoSetPresence(RTCXS_PRESENCE_OUT_TO_LUNCH);
break;
}
OnNotify
这里处理了树形控件相关的一些消息。
int idCtrl = (int)wParam;
LPNMHDR pnmh = (LPNMHDR)lParam;
HRESULT hr;
if (pnmh->code == NM_RCLICK)
{
if ( idCtrl == IDC_BUDDYTREE ) //树形控件
{
// The user clicked on the buddy list
TVHITTESTINFO tvht;
ZeroMemory(&tvht, sizeof(TVHITTESTINFO));
POINT pt;
GetCursorPos(&pt);
tvht.pt = pt;
MapWindowPoints(NULL, pnmh->hwndFrom, &tvht.pt, 1 );
HTREEITEM htriRes = TreeView_HitTest(pnmh->hwndFrom, &tvht);
if (htriRes == NULL)
{
// TreeView_HitTest failed
return 0;
}
if (tvht.flags & TVHT_ONITEM)
{
// The user clicked on a buddy
TVITEMEX tvi;
ZeroMemory(&tvi, sizeof(TVITEM));
tvi.mask = TVIF_PARAM;
tvi.hItem = htriRes;
// Get the buddy item
if (!TreeView_GetItem(m_hBuddyTree, &tvi))
{
// TreeView_GetItem failed;
return 0;
}
if (tvi.lParam == NULL)
{
// We're on a parent, not a buddy. Return.
return 0;
}
IRTCBuddy * pBuddy = (IRTCBuddy *)(tvi.lParam);
// Get the buddy URI
BSTR bstrURI = NULL;
hr = pBuddy->get_PresentityURI(&bstrURI);
if (FAILED(hr))
{
// get_UserURI failed
return 0;
}
// Get the buddy name
BSTR bstrName = NULL;
IRTCBuddy2 *pBuddy2;
pBuddy->QueryInterface(__uuidof(IRTCBuddy2), (LPVOID *)&pBuddy2);
hr = pBuddy2->get_PresenceProperty(RTCPP_DISPLAYNAME, &bstrName);
SAFE_RELEASE(pBuddy2);
if (FAILED(hr) && (hr != RTC_E_NOT_EXIST))
{
// get_Name failed
SAFE_FREE_STRING(bstrURI);
return 0;
}
// Show the buddy menu
HMENU hMenuRes = LoadMenu(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDR_MENU_BUDDY));
HMENU hMenu = GetSubMenu(hMenuRes, 0);
// Show the popup menu
UINT uID = TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON |
TPM_NONOTIFY | TPM_RETURNCMD,
pt.x, pt.y, 0, m_hWnd, NULL);
switch (uID)
{
case ID_BUDDY_CALL:
// Call the buddy
DoCall(RTCST_PC_TO_PC, bstrURI, bstrName);
break;
case ID_BUDDY_MESSAGE:
// Send a message to the buddy
DoCall(RTCST_MULTIPARTY_IM, bstrURI, bstrName);
break;
case ID_BUDDY_REFRESH:
// Refresh the buddy
DoRefreshBuddy(pBuddy);
break;
case ID_BUDDY_REMOVE:
// Remove the buddy
if (SUCCEEDED(DoRemoveBuddy(pBuddy)))
{
// Release the buddy reference
SAFE_RELEASE(pBuddy);
// Delete the buddy from the tree
TreeView_DeleteItem(m_hBuddyTree, htriRes);
}
break;
case ID_BUDDY_PROPERTIES:
//Display Presence Property Dialog
DoBuddyProperties(pBuddy);
break;
}
SAFE_FREE_STRING(bstrURI);
}
}
}
OnRTCEvent
在这里处理各种RTC相关的消息,应该给与关注。这里的处理方式几乎使用了相同的模式,都是适用QueryInterface获取事件相关的接口,然后调用相应的函数。
IDispatch * pDisp = (IDispatch *)lParam;
RTC_EVENT enEvent = (RTC_EVENT)wParam;
HRESULT hr;
switch ( enEvent )
{
case RTCE_REGISTRATION_STATE_CHANGE: //状态变化
{
IRTCRegistrationStateChangeEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCRegistrationStateChangeEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCRegistrationStateChangeEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_SESSION_STATE_CHANGE:
{
IRTCSessionStateChangeEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCSessionStateChangeEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCSessionStateChangeEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_PARTICIPANT_STATE_CHANGE:
{
IRTCParticipantStateChangeEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCParticipantStateChangeEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCParticipantStateChangeEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_MESSAGING:
{
IRTCMessagingEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCMessagingEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCMessagingEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_MEDIA:
{
IRTCMediaEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCMediaEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCMediaEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_MEDIA_REQUEST:
{
IRTCMediaRequestEvent *pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCMediaRequestEvent), (void **) &pEvent);
if (SUCCEEDED(hr))
{
OnRTCMediaRequestEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_INTENSITY:
{
IRTCIntensityEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCIntensityEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCIntensityEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_CLIENT:
{
IRTCClientEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCClientEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCClientEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_BUDDY:
{
IRTCBuddyEvent2 * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCBuddyEvent2),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCBuddyEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_WATCHER:
{
IRTCWatcherEvent2 * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCWatcherEvent2),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCWatcherEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_GROUP:
{
IRTCBuddyGroupEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCBuddyGroupEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCBuddyGroupEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_USERSEARCH:
{
IRTCUserSearchResultsEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCUserSearchResultsEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCUserSearchResultsEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_ROAMING:
{
IRTCRoamingEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCRoamingEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCRoamingEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_PROFILE:
{
IRTCProfileEvent2 * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCProfileEvent2),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCProfileEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_PRESENCE_PROPERTY:
{
IRTCPresencePropertyEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCPresencePropertyEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCPresencePropertyEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_PRESENCE_DATA:
{
IRTCPresenceDataEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCPresenceDataEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCPresenceDataEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
case RTCE_PRESENCE_STATUS:
{
IRTCPresenceStatusEvent * pEvent = NULL;
hr = pDisp->QueryInterface( __uuidof(IRTCPresenceStatusEvent),
(void **)&pEvent );
if (SUCCEEDED(hr))
{
OnRTCPresenceStatusEvent(pEvent);
SAFE_RELEASE(pEvent);
}
}
break;
}
// 释放
SAFE_RELEASE(pDisp);
其他
在该类中还包含了一些辅助函数,用于操作树形控件。
TreeViewHelper_FindBuddyNode
用于查找树形控件中的节点,这个节点包含了IRTCBuddy的数据。
TreeViewHelper_InsertNode
插入节点,该节点包含数据IRTCBuddy。
RemoveSession
删除会话CRTCSession。
RemoveUserSearch
删除用户搜索信息
RemoveWatchers
删除监测信息
RemoveGroups
删除群组
GetUserURI
获取用户的URI信息
GetUserName
获取用户名
GetCookie
获取Cookie
DoAddBuddy
增加网友
DoCall
呼叫