以前总结的关于MFC的一些知识

1. IP 控件的使用

// CString   IP 地址在 IPAddressCtrl 中显示  
  CString   strIP="192.168.0.10";  
  DWORD   dwIP;  
  dwIP   =   inet_addr(strIP);  
  unsigned   char   *pIP   =   (unsigned   char*)&dwIP;  
  m_ipAddr.SetAddress(*pIP,   *(pIP+1),   *(pIP+2),   *(pIP+3));  
   
  //
IPAddressCtrl 中的 IP 地址获得并转换成 CString  
  unsigned   char   *pIP;  
  CString   strIP;  
  DWORD   dwIP;  
  m_ipAddr.GetAddress(dwIP);  
  pIP   =   (unsigned   char*)&dwIP;  
  strIP.Format("%u.%u.%u.%u",*(pIP+3),   *(pIP+2),   *(pIP+1),   *pIP);

 

DWORD dwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

addrTo.sin_addr.S_un.S_addr = htonl(dwIP);

 

2. 端口号

  那么 TCP/IP 协议中的端口指的是什么呢?如果把 IP 地址 比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个 IP 地址的端口 可以有 65536 个之多!端口是通过端口号来标记的,端口号只有整数,范围是从 0 65535

  端口有什么用呢?我们知道,一台拥有 IP 地址的主机可以提供许多服务,比如 Web 服务、 FTP 服务、 SMTP 服务等,这些服务完全可以通过 1 IP 地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠 IP 地址,因为 IP 地址与网络服务的关系是一对多的关系。实际上是通过 “IP 地址 + 端口号 来区 分不同的服务的。

服务器一般都是通过知名端口号来识别的。例如,对于每个 TCP/IP 实现来说, FTP 服务器的 TCP 端口号都是 21 ,每个 Telnet 服务器的 TCP 端口号都是 23 ,每个 TFTP( 简单文件传送协议 ) 服务器的 UDP 端口号都是 69 。任何 TCP/IP 实现所提供的服务都用知名的 1 1023 之间的端口号。这些知名端口号由 Internet 号分配机构( InternetAssignedNumbersAuthority,IANA )来管理。

 

 

3.static member function

The declaration of a static member function is the same as that of a nonstatic member function except that the function declaration in the class body is preceded with the keyword static and the function may not be declared as const or volatile . The function definition that appears outside of the class body must not specify the keyword static .

A static member function does not have a this pointer; therefore, referring either implicitly or explicitly to the this pointer within a static member function results in a compile-time error. Attempting to access a nonstatic class member refers implicitly to the this pointer and thus results in a compile-time error. For example, the member function dailyReturn() presented earlier could not be declared as a static member function because it accesses the nonstatic data member _amount .

A static member function may be invoked for a class object or a pointer to a class object using the member access operators dot and arrow. A static member function can also be accessed or invoked directly using a qualified name even if no class objects are ever declared. Here is a small program to illustrate the use of static class members:

 

In general, a static data member is initialized outside the class definition. Just as in the case of member functions defined outside the class definition, the name of the static member in such a definition must be qualified by its class name. For example, here is how we might initialize _interestRate :

3 异步I/O

BOOL SOCKET_Select(SOCKET hSocket, int nTimeOut, BOOL bRead)

{

    fd_set fdset;

    timeval tv;

    FD_ZERO(&fdset);

    FD_SET(hSocket, &fdset);  //FD_SET(s, *set) Adds descriptor s to set.

    nTimeOut = nTimeOut > 1000 ? 1000 : nTimeOut;

    tv.tv_sec  = 0;

    tv.tv_usec = nTimeOut;

 

    int iRet = 0;

    if ( bRead )

    {

       iRet = select(0, &fdset, NULL , NULL, &tv);

    }

    else

    {

       iRet = select(0, NULL , &fdset, NULL, &tv);

    }

 

    if (iRet <= 0)

    {

       return FALSE;

    }

    else if (FD_ISSET(hSocket, &fdset))

    {

       return TRUE;

    }

 

    return FALSE;

}

 

 

4 关于 ANSI unicode 的宏

一、   在字符串前加一个 L 作用 :
  
  L" 我的字符串 "     表示将 ANSI 字符串转换成 unicode 的字符串,就是每个字符占用两个字节。
  strlen("asd")   =   3 ;  
  strlen(L "asd")   =   6 ;

  
二、   _T 宏可以把一个引号引起来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的( Unicode 还是 ANSI )字符处理方式
  
如果你定义了 UNICODE ,那么 _T 宏会把字符串前面加一个 L 。这时 _T("ABCD") 相当于 L"ABCD" ,这是宽字符串。
  
如果没有定义,那么 _T 宏不会在字符串前面加那个 L _T("ABCD") 就等价于 "ABCD"

 

5 任务栏托盘

1 、封装 “其他功能” 按钮响应函数:

void CChatRoomDlg::OnBnClickedOther()

{

    CPoint pt;

    CRect mRect;

    CMenu mMenu, *pMenu = NULL;

    GetDlgItem(IDC_OTHER)->GetWindowRect(&mRect);

    pt = mRect.BottomRight();

    pt.y = mRect.top+10;

    mMenu.LoadMenu(IDR_MENU1);

    pMenu = mMenu.GetSubMenu(0);

    pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);

}

 

2 、任务栏托盘函数的封装:

BOOL CChatRoomDlg::TrayMyIcon(BOOL bAdd)

{

    BOOL bRet = FALSE;

    NOTIFYICONDATA tnd;

    tnd.cbSize = sizeof(NOTIFYICONDATA);

    tnd.hWnd = m_hWnd;

    tnd.uID = IDR_MAINFRAME;

    if ( bAdd == TRUE ) {

       tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;

       tnd.uCallbackMessage = WM_TRAYICON_MSG;

       tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));

       _tcscpy_s(tnd.szTip, sizeof(tnd.szTip), _T(" 聊天室v1.0"));

       ShowWindow(SW_MINIMIZE);

       ShowWindow(SW_HIDE);

       bRet = Shell_NotifyIcon(NIM_ADD, &tnd);

    }else{

       ShowWindow(SW_SHOWNA);

       SetForegroundWindow();

       bRet = Shell_NotifyIcon(NIM_DELETE, &tnd);

    }

    return bRet;

}

 

3 、消息响应函数的添加:

#define WM_TRAYICON_MSG (WM_USER+100)

ON_MESSAGE(WM_TRAYICON_MSG, OnTrayCallBackMsg)

 

LRESULT CChatRoomDlg::OnTrayCallBackMsg(WPARAM wparam, LPARAM lparam)

{

    switch(lparam)

    {

    case WM_RBUTTONUP:

       {

           CMenu mMenu, *pMenu = NULL;

           CPoint pt;

           mMenu.LoadMenu(IDR_MENU2);

           pMenu = mMenu.GetSubMenu(0);

           GetCursorPos(&pt);

           SetForegroundWindow();

           pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);

           break;

       }

    case WM_LBUTTONDBLCLK:

       ShowWindow(SW_RESTORE);

       SetForegroundWindow();

       break;

    default:break;

    }

    return NULL;

}

 

 

4. 获得CString 指针

如果需要修改CString 中的内容,它有一个特殊的方法可以使用,那就是GetBuffer ,它的作用是返回一个可写的缓冲指针。如果只是打算修改字符或者截短字符串,例如

CString theString( (_T("Char test ")));
LPTSTR lpsz=s.GetBuffer();
/**/ /* 添加p 的代码*/
s.ReleaseBuffer();
// 使用完后及时释放

 

 

5 CString,string,char* 之间的转换

这几天经常用到的,不如记下吧。

这三种类型各有各的优点,比如CString 比较灵活,是基于MFC 常用的类型,安全性也最高,但可移植性最差。string 是使用STL 时必不可 少的类型,所以是做工程时必须熟练掌握的;char* 是从学习C 语言开始就已经和我们形影不离的了,有许多API 都是以char* 作为参数输入的。所以熟 练掌握三者之间的转换十分必要。

以下我用简单的图示指出三者之间的关系,并以标号对应转换的方法。

 

1 string to CString   

  CString.format("%s",string.c_str()); 

2 CString to string

string str(CString.GetBuffer(str.GetLength()));

3 string to char *

char *p=string.c_str();

4 char * to string

string str(char*);

5 CString to char *

strcpy(char,CString,sizeof(char));

6 char * to CString

CString.format("%s",char*);

 CStringformat 方法是非常好用的。stringc_str() 也是非常常用的,但要注意和char * 转换时,要把char 定义成为const char* ,这样是最安全的。

 

inline CString toCString(const std::string& str)
{ return CString(str.c_str()); }
//
inline std::string toStdString(const CString& cstr)
{ return std::string((LPCTSTR)cstr); }
//
// :
CString s1 = "Hello, World";
std::string s2 = toStdString(s1);
CString s3 = toCString(s2);

 

 

std::string cannot always construct from a LPCTSTR i.e. the code will fail for UNICODE builds.

As std::string can construct only from LPSTR / LPCSTR, a programmer who uses VC++ 7.x or better can utilize conversion classes such as CT2CA as an intermediary.

CString



 cs 



(



"Hello"



);




// Convert a TCHAR string to a LPCSTR
CT2CA pszConvertedAnsiString ( cs );
// construct a std::string using the LPCSTR input
std :: string strStd ( pszConvertedAnsiString );

'std::string' to 'CString ': (From Visual Studio's CString FAQs... )

std



::



string



 s



(



"Hello"



);




CString cs ( s . c_str ());

CStringT can construct from both character or wide-character strings. i.e. It can convert from char* (i.e. LPSTR) or from wchar_t* (LPWSTR).

In other words, char-specialization (of CStringT) i.e. CStringA, wchar_t-specilization CStringW, and TCHAR-specialization CString can be constructed from either char or wide-character, null terminated (null-termination is very important here) string sources.

 

 

6 解决 error LNK2019

用到了 Psapi.h 中的一些进程函数。我将 Psapi.h 包含到源代码中,但链接时出现了 4 LNK2019 错误,都是 Psapi.h 中的函数引起的无法解析的外部符号。

错误  2 error LNK2019: 无法解析的外部符号 _GetModuleFileNameExW@16 ,该符号在函数 "public: class ATL::CStringT<wchar_t,class StrTraitMFC_DLL<wchar_t,class ATL::ChTraitsCRT<wchar_t> > > __thiscall CSystemMangerDlg::GetProcessPath(unsigned long)" ( ?GetProcessPath@CSystemMangerDlg@@QAE?AV?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@K@Z ) 中被引用  SystemMangerDlg.obj 

因为编译通过了,所以应该不是缺少 Psapi.h 的原因。我就上 msdn2005 查了 LNK2019 ,不过里面列举的情况也没有和我类似。到网上搜,找了很久也没有和我类似的情况。后来看到一文章说是缺少附加依赖项。只要添加上附加依赖项,问题就解决了。添加附加依赖项的方法有:

方法 1 :在包含头文件 Psapi.h 的同时,加上一行代码 #pragma comment(lib,”psapi.lib”)

方法 2 [ 解决方案资源管理器 ]“ 项目 -> 属性 -> 配置属性 -> 连接器 -> 输入 -> 附加依赖项

虽然问题解决了,不过好像我还是不大理解依赖项这个东东!网上说的也很少。大概就是这个意思

一般大的工程软件都放在一个解决方案里面,分了好多模块(都是以工程方式组织在一起,或 dll, lib )。这样也是为了保证工程的同步开发的方便。
工程之间的链接可以动态链接:使用 LoadLibrary 装入库,也可以静态链接,在工程配置中添加附加依赖库,或者在代码中使用 #pragma comment(lib,"xxx.lib) Project->dependencies 中设置,主要是为了保证系统编译时候的顺序,既先编译无依赖项的项目,在编译其父依赖的项目。跟静态链接的效果是一样的。

 

 

7 如何获取本窗口句柄

要首先获得这个窗口所对应的对象指针   *p, 然后直接 p->m_hWnd. 如果你本身就在这个窗口类中需要这个句柄 ,this->m_hWnd 就可以了 .

VC++ 编程中常需获取控件或窗体句柄,下面总结了几种方法,还希望大家能多多补充。

1 、自身窗口句柄可用 AfxGetMainWnd 获取。
2
、系统中其他 APP 的窗口句柄可用 FindWindow 获取 ( SPY 帮一下忙 ).
    HWND hBtnClose;
    HWND hWnd=::FindWindow(NULL,"
腾讯 QQ 系统广播 ");
   if(hWnd)
  {
    hBtnClose=GetDlgItem(hWnd,2);
    if(hBtnClose)
    PostMessage(hBtnClose,BM_CLICK,NULL,NULL);
  }

3 、通过指针获取窗口句柄
   HWND hwnd = pwnd->m_hwnd; //
得到它的 HWND
4
、当我们想得到一个窗口对象( CWnd 的派生对象)指针的句柄( HWND )时,

最安全的方法是使用 GetSafeHwnd() 函数;
5
HWND GetDlgltem(HWND hDlg,int nlDDlgltem);
6
、通过控件 ID 号获取。
    CListCtrl*     pleftList   =   (CListCtrl*   )GetDlgItem(IDC_LIST1);

 

 

8 _countof Macro

Compute the number of elements in a statically-allocated array.

 

_countof(

      array

);

Parameters

array

The name of an array.

Return Value

The number of elements in the array.

 

 

 

 

 

9 窗口、控件的指针和句柄的相互转化

1 指针转化为句柄

MFC 应用程序中首先要获得窗口的指针,然后将其转化为句柄

CWnd* pWnd;

HANDLE hWnd = pWnd->GetSafeHwnd();

2 句柄转化为指针

MFC 应用程序中首先获得对话框控件的句柄,然后获得其指针

HANDLE hWnd;

GetDlgItem(IDC_xxx,&hWnd);

CWnd * pWnd = FromHandle(hWnd);

获得程序窗口指针的办法

1 获得主框架窗口指针( 任何时候都可以用,只要是MFC 程 序中)

CWnd* pWnd = AfxGetMainWnd();

2 获得对话框中控件指针

CWnd* pWnd = GetDlgItem(IDC_xxx);

3 获得对话框中某控件的句柄

HANDLE GetDlgItem(m_hDLG,m_nID_DlgItem);

4 获得 GDI 对象的句柄

HANDLE m_hGDIObj = m_pGDIObj->GetSafeHanle();

 

10 异步套接字基础: select 函数以及 FD_ZERO FD_SET FD_CLR FD_ISSET 使用说明 收藏


select
函数:  
         
系统提供 select 函数来实现多路复用输入 / 输出模型。原型:  
        #include   <sys/time.h>  
        #include   <unistd.h>   
     

select 函数:  
         
系统提供select 函数来实现多路复用输入/ 输出模型。原型:  
        #include   <sys/time.h>  
        #include   <unistd.h>  
        int   select(int   maxfd,fd_set   *rdset,fd_set   *wrset,fd_set   *exset,struct   timeval   *timeout);  
         
参数maxfd 是需要监视的最大的文件描述符值+1rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct   timeval 结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0    
  FD_ZERO,FD_SET,FD_CLR,FD_ISSET:          
参数maxfd 是需要监视的最大的文件描述符值+1rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct   timeval 结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0    
  FD_ZERO,FD_SET,FD_CLR,FD_ISSET:  
        FD_ZERO(fd_set   *fdset);
将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空 处理,所以结果是不可知的。  
        FD_SET(fd_set   *fdset);
用于在文件描述符集合中增加一个新的文件描述符。  
        FD_CLR(fd_set   *fdset);
用于在文件描述符集合中删除一个文件描述符。  
        FD_ISSET(int   fd,fd_set   *fdset);
用于测试指定的文件描述符是否在该集合中。  
  struct   timeval
结构:  
        struct   timeval{  
        long   tv_sec;//second  
        long   tv_usec;//minisecond  
  }  
  timeout
设置情况:  
        null:select
将一直被阻塞,直到某个文件描述符上发生了事件。  
        0
:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。  
       
特定的时间值:如果在指定的时间段里没有事件发生,select 将超时返回。

 

 

 

 

 

 

11. LPCTSTR,LPCSTR Cstring 互换

ansi 情况下,LPCTSTR 就是 const char*, 是常量字符串(不能修改的)。
LPTSTR 就是 char*, 即普通字符串(非常量,可修改的)。
这两种都是基本类型, 而CString C++ 类, 兼容这两种基本类型是最起码的任务了。

由于const char* 最简单(常量,不涉及内存变更,操作迅速), CString 直接定义了一个类型转换函数
operator LPCTSTR() {......}
, 直接返回他所维护的字符串。

当你需要一个const char* 而传入了CString 时, C++ 编译器自动调用 CString 重载的操作符 LPCTSTR() 来进行隐式的类型转换。
当需要CString , 而传入了 const char* 时(其实 char* 也可以),C++ 编译器则自动调用CString 的构造函数来构造临时的 CString 对象。

因此CString LPCTSTR 基本可以通用。


但是 LPTSTR 又不同了,他是 char* , 意味着你随时可能修改里面的数据,这就需要内存管理了( 如字符串变长,原来的存贮空间就不够了,则需要重新调整分配内存)
所以 不能随便的将 const char* 强制转换成 char* 使用。
楼主举的例子
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
就是这种不安全的使用方法。

这个地方使用的是强制类型转换,你都强制转换了,C++ 编译器当然不会拒绝你,但同时他也认为你确实知道自己要做的是什么。因此是不会给出警告的。
强制的任意类型转换是C(++) 的一项强大之处,但也是一大弊端。这一问题在 vc6 以后的版本( 仅针对vc 而言) 中得到逐步的改进( 你需要更明确的类型转换声明)

其实在很多地方都可以看到类似
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
地用法,这种情况一般是函数的约束定义不够完善的原因 , 比如一个函数接受一个字符串参数的输入,里面对该字符串又没有任何的修改,那么该参数就应该定义成 const char* , 但是很多初学者弄不清const 地用法,或者是懒, 总之就是随意写成了 char* 。 这样子传入CString 时就需要强制的转换一下。

这种做法是不安全的,也是不被建议的用法,你必须完全明白、确认该字符串没有被修改

CString
转换到 LPTSTR (char*), 预定的做法是调用CStringGetBuffer 函数,使用完毕之后一般都要再调用ReleaseBuffer 函数来确认修改 ( 某些情况下也有不调用ReleaseBuffer 的,同样你需要非常明确为什么这么做时才能这样子处理,一般应用环境可以不考虑这种情况)

同时需要注意的是, 在GetBuffer ReleaseBuffer 之间,CString 分配了内存交由你来处理,因此不能再调用其他的CString 函数。

CString LPCTSTR:
CString cStr;
const char *lpctStr=(LPCTSTR)cStr;

LPCTSTR
CString:
LPCTSTR lpctStr;
CString cStr=lpctStr;

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值