zoukankan      html  css  js  c++  java
  • 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  开始写邮件

     

     

     

  • 相关阅读:
    Object.keys
    数组内容深拷贝的应用
    CSS如何让页脚固定在页面底部
    vue eslint开发 关掉 tab错误提示
    input框,需要隐式显示的时候,不让它自动填充的办法
    关于BFC
    File协议与HTTP协议 以及区别
    关于缓存
    深拷贝浅拷贝 遇到了bug
    聚餐学习
  • 原文地址:https://www.cnblogs.com/For-her/p/3939357.html
Copyright © 2011-2022 走看看