1.3.1 数据报套接字编程

1.3  实现超链接

在网络应用过程中,特别是在Web程序中,超级链接用得非常普遍。其实使用VC技术,也可以实现超级链接功能。在本节的内容中,将介绍使用Visual C++ 6.0开发一个实现超级链接功能的应用程序。在开始之前,首先简单介绍与之相关的基础知识。

1.3.1  数据报套接字编程

流式套接字主要用于TCP协议,接下来将要学的数据报套接字主要用于UDP协议。数据报套接字(Datagram Socket)提供双向的通信,但没有可靠/有序/不重复的保证,所以UDP传送数据可能会收到无次序、重复的信息,甚至信息在传输过程中出现遗漏,但是传输效率较高,在网络上仍然有很多应用。

数据报套接字的编程模型如图1-15所示。

与流式套接字编程的主要区别在于,在数据传输过程中使用的是sendto()及recvfrom()这两个函数。其中sendto()函数的结构如下:

  1. int sendto(  
  2. SOCKET s,  
  3. const char FAR *buf,   
  4. int len,  
  5. int flags,  
  6. const struct sockaddr FAR *to,  
  7. int tolen  
  8. );  

 

 
(点击查看大图)图1-15  数据报套接字编程模型

recvfrom()函数的结构如下:

  1. int recvfrom(  
  2. SOCKET s,  
  3. char FAR *buf,  
  4. int len,  
  5. int flags,  
  6. struct sockaddr FAR *from,  
  7. int FAR *fromlen  
  8. );  

1.3.2  开发准备

在具体实现本实例之前,需要掌握一些与本实例有关的基础知识。

1. 超链接

超链接在本质上属于一个网页的一部分,它是一种允许我们同其他网页或站点之间进行连接的元素。各个网页链接在一起后,才能真正构成一个网站。所谓的超链接是指从一个网页指向一个目标的连接关系,这个目标可以是另一个网页,也可以是相同网页上的不同位置,还可以是一个图片,一个电子邮件地址,一个文件,甚至是一个应用程序。而在一个网页中用来超链接的对象,可以是一段文本或者是一个图片。当浏览者单击已经链接的文字或图片后,链接目标将显示在浏览器上,并且根据目标的类型来打开或运行。

2. CStatic类

CStatic类是一个静态文本框类,此类提供了一个Windows静态控件的性能。一个静态控件用来显示一个文本字符串、框、矩形、图标、光标、位图,或增强的图元文件。它可以被用来作为标签、框,或用来分隔其他的控件。创建一个静态控件分两步。首先,调用构造函数来构造此CStatic对象,然后调用Create成员函数来创建此静态控件并将它与该CStatic对象连接。如果你是在一个对话框中创建了一个静态控件(通过一个对话框资源),则当用户关闭这个对话框时,此CStatic对象被自动销毁。如果你是在一个窗口中创建了一个CStatic对象,则必须由你来销毁它。在一个窗口的堆栈中创建的CStatic对象将自动被销毁。如果你是使用new函数在堆中创建CStatic对象,则当你使用完后,必须调用delete来销毁这个CStatic对象。

在CStatic类中,最常用的成员函数是Create,其定义格式如下:

  1. BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT &rect,  
  2. CWnd *pParentWnd, UINT nID = 0xffff); 

lpszText:指定要放置在控件中的文本。若为NULL,则表示没有文本是可见的。

dwStyle:指定静态控件的窗口风格。任何静态控件风格的组合都可用于该控件。

rect:指定静态控件的位置和大小。可以是一个RECT结构或一个CRect对象。

pParentWnd:指定CStatic父窗口,通常是一个CDialog对象,不能是NULL。

nID:指定静态控件的控件ID。

CStatic类中其他成员函数的具体说明如表1-5所示。

表1-5  CStatic类成员函数

函数名称

功能描述

SetBitmap

指定要在此静态控件中显示的位图

GetBitmap

获取先前用SetBitmap设置的位图的句柄

SetIcon

指定一个要在此静态控件中显示的图标

GetIcon

获取先前用SetIcon设置的图标的句柄

SetCursor

指定要显示在此静态控件中的光标图像

GetCursor

获取先前用SetCursor设置的光标图像的句柄

SetEnhMetaFile

指定要显示在此静态控件中的增强的图元文件

GetEnhMetaFile

获取先前用SetEnhMetaFile设置的增强图元文件的句柄

1.3.3  小试牛刀--编程实现写邮件超级链接(1)

实例功能 编程实现写邮件超级链接

源码路径 光盘yuanma1Link

本实例的目的是,使用Visual C++ 6.0开发一个实现写邮件超级链接的应用程序。

1. 设计MFC窗体

使用Visual C++ 6.0创建一个MFC项目后,根据本实例的需要设计一个窗体,命名为IDD_ HLSAMPLE_DIALOG,如图1-16所示。

 
图1-16  创建的窗体

2. 具体编码

设计好窗体之后,接下来开始讲解具体的编码过程。

(1) 在文件HyperLink.h中定义继承于类CStatic的类CHyperLink,并设置与超链接相关的样式变量,例如鼠标形状、是否访问过等。具体代码如下:

  1. class CHyperLink : public CStatic  
  2. {  
  3. public:  
  4. CHyperLink();  
  5. virtual ~CHyperLink();  
  6. // 属性  
  7. public:  
  8.  
  9. public:  
  10. //设定URL  
  11. void SetURL(CString strURL);  
  12. CString GetURL() const;  
  13. //设定颜色  
  14. void SetColours(COLORREF crLinkColour, COLORREF crVisitedColour,   
  15. COLORREF crHoverColour=-1);  
  16. //获得连接颜色  
  17. COLORREF GetLinkColour() const;  
  18. //获得被访问后的颜色  
  19. COLORREF GetVisitedColour() const;  
  20. //获得鼠标移动上以后的颜色  
  21. COLORREF GetHoverColour() const;  
  22.  
  23. //设定是否被访问过  
  24. void SetVisited(BOOL bVisited=TRUE);  
  25. //获得是否被访问过  
  26. BOOL GetVisited() const;  
  27.  
  28. //设定鼠标形状  
  29. void SetLinkCursor(HCURSOR hCursor);  
  30. //获得鼠标形状  
  31. HCURSOR GetLinkCursor() const;  
  32. //设定是否有下划线  
  33. void SetUnderline(BOOL bUnderline=TRUE);  
  34. //获得是否有下划线  
  35. BOOL GetUnderline() const;  
  36. //设定是否是自动改变大小  
  37. void SetAutoSize(BOOL bAutoSize=TRUE);  
  38. BOOL GetAutoSize() const;  
  39.  
  40. public:  
  41. virtual BOOL PreTranslateMessage(MSG *pMsg);  
  42. protected:  
  43. virtual void PreSubclassWindow();  
  44. //}}AFX_VIRTUAL  
  45.  
  46. protected:  
  47. //连接到URL  
  48. HINSTANCE GotoURL(LPCTSTR url, int showcmd);  
  49. //打印错误  
  50. void ReportError(int nError);  
  51. //获得注册表信息  
  52. LONG GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata);  
  53. //调整位置  
  54. void PositionWindow();  
  55. //设定默认的鼠标形状  
  56. void SetDefaultCursor();  
  57.  
  58. // 变量  
  59. protected:  
  60. COLORREF m_crLinkColour, m_crVisitedColour; // 超级链接颜色  
  61. COLORREF m_crHoverColour;                           // 鼠标停留颜色  
  62. BOOL     m_bOverControl;                            // 是否鼠标移到控件上  
  63. BOOL     m_bVisited;                                // 是否被访问  
  64. BOOL     m_bUnderline;                              // 是否有下划线  
  65. BOOL     m_bAdjustToFit;                            // 是否自动调整控件大小  
  66. CString  m_strURL;                                  // URL  
  67. CFont    m_Font;                                        // 设定字体  
  68. HCURSOR  m_hLinkCursor;                             // 光标  
  69. CToolTipCtrl m_ToolTip;                             // 提示文字  
  70. protected:  
  71. afx_msg HBRUSH CtlColor(CDC *pDC, UINT nCtlColor);  
  72. afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message);  
  73. afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
  74. //}}AFX_MSG  
  75. afx_msg void OnClicked();  
  76. DECLARE_MESSAGE_MAP()  
  77. };  

1.3.3  小试牛刀--编程实现写邮件超级链接(2)

(2) 在文件HyperLink.cpp中定义类成员函数的具体实现,接下来开始讲解此文件的具体实现过程。

① 定义函数OnMouseMove和OnSetCursor实现鼠标移动事件,具体代码如下:

  1. //鼠标移动事件  
  2. void CHyperLink::OnMouseMove(UINT nFlags, CPoint point)   
  3. {  
  4. CStatic::OnMouseMove(nFlags, point);  
  5. //判断鼠标是否在控件上方  
  6. if (m_bOverControl)          
  7. {  
  8. CRect rect;  
  9. GetClientRect(rect);  
  10.  
  11. if (!rect.PtInRect(point))  
  12. {  
  13. m_bOverControl = FALSE;  
  14. ReleaseCapture();  
  15. RedrawWindow();  
  16. return;  
  17. }  
  18. }  
  19. else                      // 鼠标移过控件  
  20. {  
  21. m_bOverControl = TRUE;  
  22. RedrawWindow();  
  23. SetCapture();  
  24. }  
  25. }  
  26. BOOL CHyperLink::OnSetCursor(  
  27. CWnd* /*pWnd*/,   
  28. UINT /*nHitTest*/,   
  29. UINT /*message*/)   
  30. {  
  31. if (m_hLinkCursor)  
  32. {  
  33. ::SetCursor(m_hLinkCursor);  
  34. return TRUE;  
  35. }  
  36. return FALSE;  
  37. }  

 

② 定义函数PreSubclassWindow()实现鼠标移动事件,具体代码如下:

  1. void CHyperLink::PreSubclassWindow()   
  2. {  
  3. // 获得鼠标单击事件  
  4. DWORD dwStyle = GetStyle();  
  5. ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY);  
  6.  
  7. // 如果URL为空,设定为窗体名称  
  8. if (m_strURL.IsEmpty())  
  9. GetWindowText(m_strURL);  
  10.  
  11. // 同时检查窗体标题是否为空,如果为空则设定为URL  
  12. CString strWndText;  
  13. GetWindowText(strWndText);  
  14. if (strWndText.IsEmpty()) {  
  15. ASSERT(!m_strURL.IsEmpty());      
  16. SetWindowText(m_strURL);  
  17. }  
  18.  
  19. // 创建字体  
  20. LOGFONT lf;  
  21. GetFont()->GetLogFont(&lf);  
  22. lf.lfUnderline = m_bUnderline;  
  23. m_Font.CreateFontIndirect(&lf);  
  24. SetFont(&m_Font);  
  25.  
  26. PositionWindow();               // 调整窗体大小  
  27. SetDefaultCursor();             // 设定默认鼠标形状  
  28.  
  29. //创建提示信息  
  30. CRect rect;   
  31. GetClientRect(rect);  
  32. m_ToolTip.Create(this);  
  33. m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);  
  34.  
  35. CStatic::PreSubclassWindow();  
  36. }  

1.3.3  小试牛刀--编程实现写邮件超级链接(3)

③ 定义函数SetURL()和GetURL(),分别设置链接的URL地址并获取URL。具体代码如下:

  1. //设定URL   
  2. void CHyperLink::SetURL(CString strURL)  
  3. {  
  4. m_strURL = strURL;  
  5. if (::IsWindow(GetSafeHwnd())) {  
  6. PositionWindow();  
  7. m_ToolTip.UpdateTipText(strURL, this, TOOLTIP_ID);  
  8. }  
  9. }  
  10. CString CHyperLink::GetURL() const  
  11. {   
  12. return m_strURL;     
  13. }  
  14.  

 

④ 定义SetColours()、GetLinkColour()、GetVisitedColour()和GetHoverColour()函数,用于设置链接的不同访问状态下的颜色,具体代码如下:

  1. //设定颜色  
  2. void CHyperLink::SetColours(COLORREF crLinkColour, COLORREF crVisitedColour,  
  3.                             COLORREF crHoverColour /* = -1 */)   
  4. {   
  5. m_crLinkColour = crLinkColour;   
  6. m_crVisitedColour = crVisitedColour;  
  7. if (crHoverColour == -1)  
  8. m_crHoverColour = ::GetSysColor(COLOR_HIGHLIGHT);  
  9. else  
  10. m_crHoverColour = crHoverColour;  
  11. if (::IsWindow(m_hWnd))  
  12. Invalidate();   
  13. }  
  14.  
  15. COLORREF CHyperLink::GetLinkColour() const  
  16. {   
  17. return m_crLinkColour;   
  18. }  
  19.  
  20. COLORREF CHyperLink::GetVisitedColour() const  
  21. {  
  22. return m_crVisitedColour;   
  23. }  
  24.  
  25. COLORREF CHyperLink::GetHoverColour() const  
  26. {  
  27. return m_crHoverColour;  
  28. }  

 

⑤ 定义函数SetVisited()和GetVisited(),用于设置是否被访问过,具体代码如下:

  1. void CHyperLink::SetVisited(BOOL bVisited /* = TRUE */)   
  2. {   
  3. m_bVisited = bVisited;   
  4.  
  5. if (::IsWindow(GetSafeHwnd()))  
  6. Invalidate();   
  7. }  
  8.  
  9. BOOL CHyperLink::GetVisited() const  
  10. {   
  11. return m_bVisited;   
  12. }  

1.3.3  小试牛刀--编程实现写邮件超级链接(4)

⑥ 定义函数SetLinkCursor()和GetLinkCursor(),用于分别设定鼠标的形状和获取鼠标的形状,具体代码如下:

  1. void CHyperLink::SetLinkCursor(HCURSOR hCursor)  
  2. {   
  3. m_hLinkCursor = hCursor;  
  4. if (m_hLinkCursor == NULL)  
  5. SetDefaultCursor();  
  6. }  
  7.  
  8. HCURSOR CHyperLink::GetLinkCursor() const  
  9. {  
  10. return m_hLinkCursor;  
  11. }  

 

⑦ 定义函数SetUnderline()和GetUnderline(),分别用于设置是否有下划线和获取是否具有下划线,具体代码如下:

  1. //设置下划线  
  2. void CHyperLink::SetUnderline(BOOL bUnderline /* = TRUE */)  
  3. {  
  4. m_bUnderline = bUnderline;  
  5.  
  6. if (::IsWindow(GetSafeHwnd()))  
  7. {  
  8. LOGFONT lf;  
  9. GetFont()->GetLogFont(&lf);  
  10. lf.lfUnderline = m_bUnderline;  
  11. m_Font.DeleteObject();  
  12. m_Font.CreateFontIndirect(&lf);  
  13. SetFont(&m_Font);  
  14. Invalidate();   
  15. }  
  16. }  
  17.  
  18. BOOL CHyperLink::GetUnderline() const  
  19. {   
  20. return m_bUnderline;   
  21. }  

 

⑧ 定义函数SetAutoSize()和GetAutoSize(),分别用于设置和获取是否是自动改变大小,具体代码如下:

  1. void CHyperLink::SetAutoSize(BOOL bAutoSize /* = TRUE */)  
  2. {  
  3. m_bAdjustToFit = bAutoSize;  
  4. if (::IsWindow(GetSafeHwnd()))  
  5. PositionWindow();  
  6. }  
  7.  
  8. BOOL CHyperLink::GetAutoSize() const  
  9. {   
  10. return m_bAdjustToFit;   
  11. }  

 

⑨ 定义函数PositionWindow(),用于调整窗体的大小,具体代码如下:

  1. void CHyperLink::PositionWindow()  
  2. {  
  3. if (!::IsWindow(GetSafeHwnd()) || !m_bAdjustToFit)   
  4. return;  
  5. CRect rect;  
  6. GetWindowRect(rect);  
  7. CWnd *pParent = GetParent();  
  8. if (pParent)  
  9. pParent->ScreenToClient(rect);  
  10. CString strWndText;  
  11. GetWindowText(strWndText);  
  12. CDC *pDC = GetDC();  
  13. CFont *pOldFont = pDC->SelectObject(&m_Font);  
  14. CSize Extent = pDC->GetTextExtent(strWndText);  
  15. pDC->SelectObject(pOldFont);  
  16. ReleaseDC(pDC);  
  17. DWORD dwStyle = GetStyle();  
  18. if (dwStyle & SS_CENTERIMAGE)  
  19. rect.DeflateRect(0, (rect.Height() - Extent.cy)/2);  
  20. else  
  21. rectrect.bottom = rect.top + Extent.cy;  
  22. if (dwStyle & SS_CENTER)     
  23. rect.DeflateRect((rect.Width() - Extent.cx)/2, 0);  
  24. else if (dwStyle & SS_RIGHT)   
  25. rectrect.left  = rect.right - Extent.cx;  
  26. else   
  27. rectrect.right = rect.left + Extent.cx;  
  28. SetWindowPos(NULL, rect.left, rect.top,   
  29. rect.Width(), rect.Height(), SWP_NOZORDER);  
  30. }  

 

 

⑩ 定义函数SetDefaultCursor(),用于设定默认的鼠标形状,具体代码如下:

  1. void CHyperLink::SetDefaultCursor()  
  2. {  
  3. if (m_hLinkCursor == NULL)         // No cursor handle - load our own  
  4. {  
  5. // Get the windows directory  
  6. CString strWndDir;  
  7. GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);  
  8. strWndDir.ReleaseBuffer();  
  9.  
  10. strWndDir += _T("\winhlp32.exe");  
  11. // This retrieves cursor #106 from winhlp32.exe,   
  12. // which is a hand pointer  
  13. HMODULE hModule = LoadLibrary(strWndDir);  
  14. if (hModule) {  
  15. HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));  
  16. if (hHandCursor)  
  17. m_hLinkCursor = CopyCursor(hHandCursor);  
  18. }  
  19. FreeLibrary(hModule);  
  20. }  
  21. }  

 

⑪定义函数GetRegKey(),用于获得注册表信息,具体代码如下:

  1. LONG CHyperLink::GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata)  
  2. {  
  3. HKEY hkey;  
  4. LONG retval = RegOpenKeyEx(key, subkey, 0, KEY_QUERY_VALUE, &hkey);  
  5. if (retval == ERROR_SUCCESS) {  
  6. long datasize = MAX_PATH;  
  7. TCHAR data[MAX_PATH];  
  8. RegQueryValue(hkey, NULL, data, &datasize);  
  9. lstrcpy(retdata, data);  
  10. RegCloseKey(hkey);  
  11. }  
  12. return retval;  
  13. }  

⑫定义函数ReportError(),用于输出打印错误,具体代码如下:

  1. void CHyperLink::ReportError(int nError)  
  2. {  
  3. CString str;  
  4. switch (nError) {  
  5. case 0:   
  6. str = "The operating system is out of memory or resources.";   
  7. break;  
  8. case SE_ERR_PNF:   
  9. str = "The specified path was not found.";   
  10. break;  
  11. case SE_ERR_FNF:       
  12. str = "The specified file was not found.";   
  13. break;  
  14. case ERROR_BAD_FORMAT:    
  15. str = "The .EXE file is invalid (non-Win32 .EXE " 
  16. + CString("") + "or error in .EXE image).";   
  17. break;  
  18. case SE_ERR_ACCESSDENIED:   
  19. str="The operating system denied access to the specified file.";   
  20. break;  
  21. case SE_ERR_ASSOCINCOMPLETE:    
  22. str = "The filename association is incomplete or invalid.";   
  23. break;  
  24. case SE_ERR_DDEBUSY:   
  25. str = "The DDE transaction could not be completed because " 
  26. + CString("")+"other DDE transactions were being processed.";   
  27. break;  
  28. case SE_ERR_DDEFAIL:   
  29. str = "The DDE transaction failed.";   
  30. break;  
  31. case SE_ERR_DDETIMEOUT:   
  32. str = "The DDE transaction could not be completed because " 
  33. + CString("") + "the request timed out.";   
  34. break;  
  35. case SE_ERR_DLLNOTFOUND:   
  36. str = "The specified dynamic-link library was not found.";   
  37. break;  
  38. case SE_ERR_NOASSOC:   
  39. str = "There is no application associated with the " 
  40. + CString("") + "given filename extension.";   
  41. break;  
  42. case SE_ERR_OOM:   
  43. str = "There was not enough memory to complete the operation.";   
  44. break;  
  45. case SE_ERR_SHARE:   
  46. str = "A sharing violation occurred. ";  
  47. default:   
  48. str.Format("Unknown Error (%d) occurred.", nError);   
  49. break;  
  50. }  
  51.  
  52. str = "Unable to open hyperlink: " + str;  
  53. AfxMessageBox(str, MB_ICONEXCLAMATION | MB_OK);  
  54. }  

定义函数GotoURL(),用于链接到指定的目标地址,具体代码如下:

  1. //链接到目标地址  
  2. HINSTANCE CHyperLink::GotoURL(LPCTSTR url, int showcmd)  
  3. {  
  4. TCHAR key[MAX_PATH + MAX_PATH];  
  5.  
  6. // 调用函数ShellExecute()  
  7. HINSTANCE result =   
  8. ShellExecute(NULL, _T("open"), url, NULL, NULL, showcmd);  
  9.  
  10. // 如果错误,则检查注册表获得.htm文件的注册键值  
  11. if ((UINT)result <= HINSTANCE_ERROR) {  
  12.  
  13. if (GetRegKey(HKEY_CLASSES_ROOT,_T(".htm"),key) == ERROR_SUCCESS) {  
  14.  
  15. lstrcat(key, _T("\shell\open\command"));  
  16.  
  17. if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS) {  
  18. TCHAR *pos;  
  19. pos = _tcsstr(key, _T(""%1""));  
  20. if (pos == NULL) {                     // 没有发现  
  21. pos = strstr(key, _T("%1"));       // 检查%1  
  22. if (pos == NULL)                   // 没有参数  
  23. pos = key+lstrlen(key)-1;  
  24. else  
  25. *pos = '';                   // 删除参数  
  26. }  
  27. else  
  28. *pos = '';                       // 删除参数  
  29.  
  30. lstrcat(pos, _T(" "));  
  31. lstrcat(pos, url);  
  32. result = (HINSTANCE)WinExec(key, showcmd);  
  33. }  
  34. }  
  35. }  
  36.  
  37. return result;  
  38. }  

 

至此,整个实例的主要模块介绍完毕。该程序执行后,将在窗体内显示一个超级链接,如图1-17所示。单击"写邮件"后,将激活链接,开始写邮件,如图1-18所示。

 
图1-17  显示一个超级链接
 
图1-18  开始写邮件

 

 

 

原文地址:https://www.cnblogs.com/For-her/p/3939357.html