用VC++编写网络计时工具
我们的程序界面如图(如^49020401a^1),当按下确定时,它会最小化到系统托盘区。将鼠标移到它的图标上,如果你已经连到了网上,就会显示连网的时间和费用; 如果你没有连网,那么就显示“未连接”。图中的三个编辑框分别显示连接时间,上网方式(有拨号上网、局域上网等)和即时费用。按下设置键,会弹出一个对话框,要求你输入每小时的收费(如^49020401b^2)。
下面我们来一步一步实现这个程序的各项功能。
用AppWizard建立一个基于对话框的MFC应用程序NetTimer。我们先将程序外观和变量定义的工作做完。
在资源编辑区内编辑对话框,最终结果如图1。设置三个静态文本的ID分别为IDC_STATIC_SHOWTIME,IDC_STATIC_METHOD和IDC_STATIC_FEE,三个编辑框的ID分别为IDC_EDIT_SHOWTIME,IDC_EDIT_METHOD和IDC_EDIT_FEE,“确定”按钮的ID是IDOK,“设置”按钮是IDC_BUTTON_SETUP。添加一个新的对话框IDD_DIALOG1,最终结果如图2,编辑框的ID号是IDC_EDIT_YUAN.
在NetTimerDlg.h的protected区添加如下变量:
CString m_strFee;
CString m_strTime;
int m_iTime;
BOOL m_bConnected;
LPDWORD flags;
在它的构造函数里分别初始化如下:
m_bConnected = FALSE;
m_iTime = 0;
m_strTime = ″″;
flags = new DWORD;
m_strFee = ″″;
首先实现程序最小化时在系统区显示图标的功能。为“确定”按钮对应的OnOk事件响应函数写入如下代码:
NOTIFYICONDATA nc;
nc.cbSize = sizeof(NOTIFYICONDATA);
nc.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
nc.hWnd = m_hWnd;
lstrcpy(nc.szTip,″hello″);
nc.uCallbackMessage = WM_NC;//自定义的消息
nc.uID = IDC_NC;
nc.uFlags = NIF_TIP | NIF_MESSAGE | NIF_ICON;
Shell_NotifyIcon(NIM_ADD,&nc); //在托盘区显示IDR_MAINFRAME对应的图标
ShowWindow(false);//隐藏窗口
然后在NetTimerDlg.cpp的文件头部写入:
#define WM_NC 1001
#define IDC_NC 1002
以上代码中关键的函数是Shell_NotifyIcon,第一个参数表示你要增加、修改还是删除图标;第二个参数是一个NOTIFYICONDATA结构变量对应的地址,它的主要作用是提供必要的信息,使托盘区图标能够正常工作。需要注意的一点是一定要把原先默认的CButton::OnOk();语句从函数里删除,否则程序会在每次按下回车之后就自动退出。
下面代码是双击图标时的响应函数:
void CNetTimerDlg::OnNc(WPARAM wParam,LPARAM lParam)
{ switch(lParam)
{ case WM_LBUTTONDBLCLK://如果是双击图标
ShowWindow(true);//显示窗口
break;
case WM_MOUSEMOVE://如果鼠标移动到了图标对应的矩形区域
NOTIFYICONDATA nc; //以下代码用来显示当前连接时间和上网费用,如果没有连接则显示“未连接”
nc.cbSize = sizeof(NOTIFYICONDATA);
nc.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
nc.hWnd = m_hWnd;
nc.uCallbackMessage = WM_NC;
nc.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON;
nc.uID = IDC_NC;
if(m_bConnected)
lstrcpy(nc.szTip,m_strTime + ″\n″ + m_strFee);
else
lstrcpy(nc.szTip,″未连接″);
Shell_NotifyIcon(NIM_MODIFY,&nc);
break;}}
别忘了在NetTimerDlg.h里定义函数:
afx_msg void OnNc(WPARAM wParam,LPARAM lParam);
同时在NetTimerDlg.cpp的BEGIN_MESSAGE_MAP(CNetTimerDlg,CDialog)和BEGIN_MESSAGE_MAP(CNetTimerDlg,CDialog)之间插入ON_MESSAGE(WM_NC,OnNc),用来申明对该消息的响应函数为OnNc。
下面在CNetTimerDlg的OnInitDialog函数后部(return TRUE;语句前)加入:
SetTimer(1,1000,NULL); //设置一个时钟,编号是1,每过1秒钟响应一次。
用ClassWizard为WM_TIMER加一个响应函数,代码如下:
void CNetTimerDlg::OnTimer(UINT nIDEvent)
{ m_bConnected = ::InternetGetConnectedState(flags,NULL); //判断是否连网的API
if(m_bConnected) //如果连网
OnConnected();//处理连网情况下的函数
else//如果没有连网
OnDisconnected();//处理未连网情况下的函数
CDialog::OnTimer(nIDEvent);}
以上代码中的InternetGetConnectedState是一个API函数,用来判断当前是否处于连网状态。它的第一个参数是一个指向DWORD类型的指针,用于接收上网方式的信息。第二个参数由系统保留,指定为NULL。
由于我们用到了有关网络的函数,所以在文件头部得添加一句:
#include ″afxinet.h″
接下去分别定义OnConnected和OnDisconnected函数:
void CNetTimerDlg::OnConnected()
{ int hour = 0;//定义小时,分,秒
int minute = 0;
int second = 0;
if (m_iTime < 60) //如果总的时间少于60秒...
{ hour = 0;
minute = 0;
second = m_iTime;}
if (m_iTime >= 60 && m_iTime < 3600)//如果大于60小于3600
{ hour = 0;
minute = m_iTime / 60;
second = m_iTime - minute * 60;}
if (m_iTime >= 3600) //如果大于3600
{ hour = m_iTime / 3600;
minute = (m_iTime - hour * 3600) / 60;
second = m_iTime - 60 * minute - 3600 * hour;}
m_iTime ++;//累加
m_strTime.Format(″%d小时 %d分 %d秒″,hour,minute,second); //格式化数据SetDlgItemText(IDC_EDIT_SHOWTIME,m_strTime);//显示连网时间
switch(*flags) //判断以什么方式上网
{ case INTERNET_CONNECTION_MODEM://拨号上网
SetDlgItemText(IDC_EDIT_METHOD,″拨号上网″);
break;
case INTERNET_CONNECTION_LAN://通过局域网上网
SetDlgItemText(IDC_EDIT_METHOD,″通过局域网上网″);
break;
case INTERNET_CONNECTION_PROXY: //通过代理服务器
SetDlgItemText(IDC_EDIT_METHOD,″通过代理服务器上网″);
break;
case INTERNET_CONNECTION_MODEM_BUSY://Modem忙于其他
SetDlgItemText(IDC_EDIT_METHOD,″Modem正忙,但不是上网″);
break;}
double value;//以下用于显示上网费用
m_strFee = AfxGetApp() ->GetProfileString(″Fee section″,″fee″,NULL);
//得到保存在文件中的相应数据
value = atof(m_strFee);
//调用atof函数将文字信息转化为double类型
value = value * m_iTime / 3600;
m_strFee.Format(″%lf元″,value);
SetDlgItemText(IDC_EDIT_FEE,m_strFee);
//显示费用}
void CNetTimerDlg::OnDisconnected()
{ SetDlgItemText(IDC_EDIT_SHOWTIME,″未连接″);//在编辑框中显示“非连接”
m_iTime = 0;}
然后分别在NetTimerDlg.h中定义如下:
public:
void OnDisconnected();
void OnConnected();
下一步为ID号为IDD_DIALOG1的对话框建立一个新类CFeeDlg,并且在NetTimerDlg.cpp头部添加:
#include ″FeeDlg.h″
然后为它的“确定”按钮添加响应函数如下:
void CFeeDlg::OnOK()
{ CString text;
GetDlgItemText(IDC_EDIT_YUAN,text);//获取编辑框IDC_EDIT_YUAN中的输入:
AfxGetApp() ->WriteProfileString(″Fee section″,″fee″,text);//写入文件
CDialog::OnOK();}
然后回过头来为CNetTimerDlg的“设置”按钮添加响应函数如下:
void CNetTimerDlg::OnButtonSetup()
{ CFeeDlg FeeDlg;
FeeDlg.DoModal();}
最后,别忘了做一些必要的编译设置:因为我们用到了wininet.lib库,所以别忘了在“工程/设置”菜单下的link选项卡里将“对象/库模块”一项设为Wininet.lib。
OK,最后到网上下载个漂亮的图标替代VC默认的那个图标,编译工程文件,一个属于你自己的网络计时工具就产生了!
注:本程序在Windows 98,Visual C++ 6.0下通过。