📄 csdn_文档中心_myicq情景分析.htm
字号:
name=第一个情景></A>1.第一个情景:用户注册<BR>这个情景主要用到的数据结构:<BR>(1)IcqUser<BR>让我们先来看IcqUser的代码,<BR>class
IcqUser : public IcqInfo {<BR>public:<BR>IcqUser();<BR><BR>void
load(DBInStream &in);<BR>void save(DBOutStream
&out);<BR><BR>string passwd;<BR>uint8 auth;<BR>};<BR>class
IcqInfo : public ContactInfo, public DBSerialize
{<BR>public:<BR>IcqInfo();<BR>virtual ~IcqInfo() {}<BR><BR>void
save(DBOutStream &out);<BR>void load(DBInStream
&in);<BR>};<BR>class ContactInfo {<BR>public:<BR>QID
qid;<BR>string nick;<BR>uint8 face;<BR>uint8 gender;<BR>uint8
age;<BR>string country;<BR>string province;<BR>string
city;<BR><BR>string email;<BR>string address;<BR>string
zipcode;<BR>string tel;<BR><BR>string name;<BR>uint8
blood;<BR>string college;<BR>string profession;<BR>string
homepage;<BR>string intro;<BR><BR>uint32 status;<BR>};<BR>class
DBSerialize {<BR>public:<BR>virtual void save(DBOutStream &out)
= 0;<BR>virtual void load(DBInStream &in) =
0;<BR>};<BR>很明显可以看出它是用来存储人员基本信息的数据结构,它有两个方法save和load,我们来看看它们的代码,<BR>可以想出它是用来将数据成员存入数据库和从数据库读出.DBSerialize是一个抽象类。
<BR>void IcqUser::load(DBInStream
&in)<BR>{<BR>IcqInfo::load(in);<BR><BR>in >> passwd
>> auth;<BR>}<BR><BR>void IcqUser::save(DBOutStream
&out)<BR>{<BR>IcqInfo::save(out);<BR><BR>out << passwd
<< auth;<BR>}<BR>void IcqInfo::load(DBInStream
&in)<BR>{<BR>in >> face >> nick >> age
>> gender >> country >> province >>
city;<BR>in >> email >> address >> zipcode
>> tel;<BR>in >> name >> blood >> college
>> profession >> homepage >>
intro;<BR>}<BR><BR>void IcqInfo::save(DBOutStream
&out)<BR>{<BR>out << face << nick << age
<< gender << country << province <<
city;<BR>out << email << address << zipcode
<< tel;<BR>out << name << blood << college
<< profession << homepage <<
intro;<BR>}<BR>/*<BR>* Utility class that reads from or writes to a
data block<BR>*/<BR>class DBOutStream {<BR>public:<BR>DBOutStream()
{<BR>cursor = data;<BR>}<BR>char *getData() {<BR>return
data;<BR>}<BR>int getSize() {<BR>return (cursor -
data);<BR>}<BR><BR>DBOutStream &operator <<(uint8
b);<BR>DBOutStream &operator <<(uint16 w);<BR>DBOutStream
&operator <<(uint32 dw);<BR>DBOutStream &operator
<<(const char *str);<BR>DBOutStream &operator
<<(StrList &strList);<BR>DBOutStream &operator
<<(const string &str) {<BR>return operator
<<(str.c_str());<BR>}<BR>DBOutStream &operator
<<(const QID &qid) {<BR>return (*this << qid.uin
<< qid.domain);<BR>}<BR><BR>private:<BR>char
data[MAX_BLOCK_SIZE];<BR>char *cursor;<BR>};<BR>class DBInStream
{<BR>public:<BR>DBInStream(void *d, int n) {<BR>cursor = data =
(char *) d;<BR>datalen = n;<BR>}<BR>DBInStream &operator
>>(uint8 &b);<BR>DBInStream &operator >>(uint16
&w);<BR>DBInStream &operator >>(uint32
&dw);<BR>DBInStream &operator >>(string
&str);<BR>DBInStream &operator >>(StrList
&strList);<BR>DBInStream &operator >>(QID &qid)
{<BR>return (*this >> qid.uin >>
qid.domain);<BR>}<BR><BR>private:<BR>char *data;<BR>char
*cursor;<BR>int datalen;<BR>};<BR><BR>(2)IcqOption<BR>class
IcqOption : public DBSerialize
{<BR>public:<BR>IcqOption();<BR>virtual ~IcqOption();<BR><BR>void
load(DBInStream &in);<BR>void save(DBOutStream
&out);<BR>void playSound(int sound, IcqContact *c =
NULL);<BR><BR>bitset<NR_USER_FLAGS> flags; // System option
flags<BR>uint32 hotKey;<BR>string soundFiles[NR_SOUNDS];<BR>string
host;<BR>uint16 port;<BR>string autoReplyText;<BR>string
quickReplyText;<BR>uint32 autoStatus;<BR>uint32
autoStatusTime;<BR>string skin;<BR><BR>// Proxy stuff<BR>uint8
proxyType;<BR>ProxyInfo
proxy[NR_PROXY_TYPES];<BR><BR>private:<BR>bool playSound(const char
*file);<BR>};<BR>存储各种选项<BR><BR>在这个情景里,我们假定用户已经点击网络设置那一页的下一步按钮。进入以下代码中:<BR>BOOL
CRegFinishDlg::OnSetActive() <BR>{<BR>206 CRegWizard *wiz =
(CRegWizard *) GetParent();<BR>207
wiz->getData(&icqLink->myInfo,
&icqLink->options);<BR><BR>首先206行取到上个窗口的指针,就是属性表的指针,进而调用它的函数getData。进入代码:<BR>CRegFinishDlg::OnSetActive()-->CRegWizard::getData()<BR><BR>54
void CRegWizard::getData(IcqUser *info, IcqOption *options) <BR>55 {
<BR>56 if (modeDlg.m_mode == 0) <BR>57 info->qid = qid; <BR>58
else { <BR>59 info->qid.uin = modeDlg.m_uin; <BR>60
info->qid.domain = finishDlg.domain; <BR>61 } <BR>62 <BR>63
info->face = basicDlg.m_pic; <BR>64 info->age =
basicDlg.m_age; <BR>65 info->nick = basicDlg.m_nick; <BR>66
info->gender = basicDlg.m_gender; <BR>67 info->country =
basicDlg.m_country; <BR>68 info->province = basicDlg.m_province;
<BR>69 info->city = basicDlg.m_city; <BR>70 <BR>71 info->email
= commDlg.m_email; <BR>72 info->address = commDlg.m_address;
<BR>73 info->zipcode = commDlg.m_zipcode; <BR>74 info->tel =
commDlg.m_tel; <BR>75 <BR>76 info->name = miscDlg.m_name; <BR>77
info->blood = miscDlg.m_blood; <BR>78 info->college =
miscDlg.m_college; <BR>79 info->profession =
miscDlg.m_profession; <BR>80 info->homepage = miscDlg.m_homepage;
<BR>81 info->intro = miscDlg.m_intro; <BR>82 <BR>83
info->passwd = (modeDlg.m_mode == 0 ? basicDlg.m_passwd :
modeDlg.m_passwd);<BR>84 <BR>85 if (options) { <BR>86
options->host = networkDlg.m_host; <BR>87 options->port =
networkDlg.m_port; <BR>88 options->flags.set(UF_USE_PROXY,
networkDlg.m_useProxy); <BR>89 options->proxyType =
networkDlg.m_proxyType; <BR>90 for (int i = 0; i <
NR_PROXY_TYPES; ++i) <BR>91 options->proxy[i] =
networkDlg.proxyInfo[i]; <BR>92 } <BR>93
}<BR>此方法传入两个结构IcqUser和IcqOption以上有说明<BR>第56行到第61行,主要给qid赋值,modeDlg.m_mode如选中新申请一个QQ号则为0,选中已有QQ号为1,本情景为0,也就是将info->qid
= qid; qid是IcqWindow的一个公有变量QID qid</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">class QID
{<BR>public:<BR>QID() {<BR>uin = 0;<BR>}<BR>bool operator ==(const
QID &qid) {<BR>return (uin == qid.uin &&
!strcasecmp(domain.c_str(), qid.domain.c_str()));<BR>}<BR>bool
isAdmin() {<BR>return (uin == ADMIN_UIN &&
domain.empty());<BR>}<BR>char *toString();<BR>bool parse(const char
*qid);<BR><BR>uint32 uin;<BR>string
domain;<BR>};<BR>剩下的代码就是根据这几个对话框所添入的东东给全局变量icqLink中的IcqUser和IcqOption的各成员变量赋值.<BR>回到RegFinishDlg::OnSetActive()
中第208行开始,<BR>208 wiz->qid.uin = 0;<BR>209<BR>210 CString
str;<BR>211 str.LoadString(IDS_PLEASE_WAIT);<BR>212
SetDlgItemText(IDC_STATUS, str);<BR>213
str.LoadString(IDS_REG_REGISTERING);<BR>214
SetDlgItemText(IDC_STATUS_DETAIL, str);<BR>215
wiz->SetWizardButtons(PSWIZB_DISABLEDFINISH);<BR>216<BR>217
m_faceLabel.start();<BR>218<BR>219 resolveHost();<BR>220<BR>221
return
CPropertyPage::OnSetActive();<BR>}<BR>这行将MyIcq号赋为0,211-218设置一些状态,219进入CRegFinishDlg::resolveHost()</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
CRegFinishDlg::resolveHost()<BR>{<BR>172 CRegWizard *wiz
= (CRegWizard *) GetParent();<BR>173 const char *host =
wiz->networkDlg.m_host;<BR>174<BR>175 if
(wiz->networkDlg.m_useProxy &&
!wiz->networkDlg.m_proxyResolve)<BR>176
getUdpSession()->connect(host,
wiz->networkDlg.m_port);<BR>177 else
{<BR>178 struct in_addr
addr;<BR>179 addr.s_addr =
inet_addr(host);
//将x.x.x.x转换为无符号整数给addr.s_addr<BR>180
if (addr.s_addr !=
INADDR_NONE)<BR>181
onHostFound(addr);<BR>182
else<BR>183
((CIcqDlg *)
AfxGetMainWnd())->getHostByName(host);<BR>
}<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">175行看出在网络设置对话框中有没有选使用代理服务器,本情景中没选到178行将用户选定的地址作为参数传给onHostFound(addr);进入onHostFound</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
CRegFinishDlg::onHostFound(struct in_addr
&addr)<BR>{<BR>163 if (addr.s_addr != INADDR_NONE)
{<BR>164 CRegWizard *wiz =
(CRegWizard *)
GetParent();<BR>165
getUdpSession()->connect(inet_ntoa(addr),
wiz->networkDlg.m_port);<BR>166 }
else<BR>167
onTimeout();<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">在165行调用函数getUpdSession()->connect传入参数是用户输入的地址和端口。</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">inline UdpSession
*getUdpSession()<BR>{<BR> return
icqLink->udpSession;<BR>}</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
UdpSession::connect(const char *host, uint16
port)<BR>{<BR>090 IcqOption &options =
icqLink->options;<BR>091<BR>092 // Connect using
proxy<BR>093 if (options.flags.test(UF_USE_PROXY))
{<BR>094 if (options.proxyType
==
PROXY_SOCKS)<BR>095
socksProxy.start(options.proxy[PROXY_SOCKS],
sock);<BR>096 else if
(options.proxyType ==
PROXY_HTTP)<BR>097
httpProxy.start(host, options.proxy[PROXY_HTTP]); }
<BR>099 else{ //not use proxy</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">100
sockaddr_in addr;<BR>101
socklen_t len =
sizeof(addr);<BR>103
memset(&addr, 0,
sizeof(addr));<BR>104
addr.sin_family =
AF_INET;<BR>105 addr.sin_port =
htons(port);<BR>106
addr.sin_addr.s_addr =
inet_addr(host);<BR>107
::connect(sock, (sockaddr *) &addr,
len);<BR>109 getsockname(sock,
(sockaddr *) &addr,
&len);<BR>110 realIP =
ntohl(addr.sin_addr.s_addr);<BR>112
icqLink->onConnect(true);</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">
}<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">首先判断有没有用proxy本情景中没有用所以到100行调用几个SOCKET函数连接传入的服务器及端口,将真实IP存放在realIP中,然后调用icqLink->onConnect(true);这个函数是一个虚函数,</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">CicqDlg类改写了它
,所以程序进入CIcqDlg::onConnect</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
CIcqDlg::onConnect(bool success)<BR>{<BR>292 IcqWindow *win =
findWindow(WIN_REG_WIZARD);</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">进入findWindow</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">IcqWindow
*IcqLink::findWindow(int type, QID *qid, uint32
seq)<BR>{<BR> PtrList::iterator
it;<BR> for (it = windowList.begin(); it !=
windowList.end(); ++it)
{<BR> IcqWindow *win =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -