快考完了。。。

还剩一科就考完了。。后天就回家。。又到了每年回家的时候了。。。前几科“考”的还不错。。哈哈

我的小木马也能跑起来喽。。可以进行远程文件管理了。。。

回家继续完善,要完善的东西还很多。。我一定会完成我的心愿的!我相信!

VC 类向导添加变量出错 Unhandled exception in snmp.exe:0xC0000005:Access Violation

无厘头的问题。。幸好网上有高人。。解决了。。呵呵

vc++的确很方便,为我们做了不少的事情,但是有的时候却令我们很郁闷,特别是遇到一些无厘头的问题的时候。

就像今天的这个,快把我气死了,我调了一个小时,居然又莫名奇妙的好了,??????

微软的东西真是强啊!不过人无完人,能做到这样已经不错了,不过我更希望看到国人的软件

废话不说了,简述下问题的起因:

今天需要编写一个串口通信的程序,于是直接哪来以前的一个实例程序,添加一个COMBO BOX控件,编译连接 运行,没有错误。然后用类向导给此控件加一个control型变量,名字是m_ctrlloop,编译时出现一个对话框,大意曰“有外部编辑器改写了程序”,我的心头飘过一层不祥的预感,但是,编译连接,错误为0点击运行,没反应,(难道鼠标飘了)再点,点,我点,点,点。。。。

还是没反应,不禁让我联想到以前在机房遇到的类似的问题,正好当时下课了,所以没有深究,没想到今天又碰到了。

首先想到的就是调试了,呵呵,很不幸,一点go,便弹出个对话框。曰:“ Unhandled exception in snmp.exe:0xC0000005:Access Violation”。这可怎么办呢?

上网查了一些资料,未果,现在又莫名的好了,把我的解决方法简要说下,未必有效,但及时总结经验总是没有错的,呵呵。

我觉得类向导有偷懒的嫌疑,所以先以程序原先定义的一个combo box的控制型变量搜索,查到如下:

1,在XXXDlg.h 中有:

// Dialog Data

//{{AFX_DATA(CSerialCommDlg)

CComboBox m_ctrlCOMName;

2,在XXXDlg.cpp中有:

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CSerialCommDlg)

DDX_Control(pDX, IDC_COM_NAME, m_ctrlCOMName);

3,在XXXDlg.h 中有:

// Dialog Data

//{{AFX_DATA(CSerialCommDlg)

CComboBox m_ctrlCOMName;

你可能已经发现了一个问题,就是1和3明明是一样的,为什么还写出来呢,其实我也很纳闷,按理说1和3在同一个文件中,但是对比后我发现,用 查找 寻找时这个地方要显示两次的,而且由于我改的比较乱,发现居然二者的代码不一样,如此而言,就很有可能是临时文件搞的鬼了。

参照网上的一种说法,有为同仁在遇到这种问题的时候:将.ncb和.opt文件删除后,重新编译,就OK了

http://topic.csdn.net/t/20051021/11/4341390.html

当然也不尽全是vc 的错误,好多的问题也会提示这个问题,但是如果是0xC0000005就很可能是这个问题了

相关的资料:

http://topic.csdn.net/t/20061225/09/5253265.html

http://zhidao.baidu.com/question/43921217.html

http://zhidao.baidu.com/question/52230148.html

结论:引用一位高人的话,呵呵

为什么有时候代码对的,却编译报错:Cannot open precompiled header ,或者类的成员不能出来?

1。检查 *.cpp 里有没有包含 #include “stdafx.h”
2。删除 debug 目录

3。删除 *.ncb文件 支持ClassView

4。删除 *.clw文件 支持ClassWizard

5。删除 *.aps文件 支持ResourceView
6。删除 *.opt文件 保存工作空间的配置(如果删除此文件,特殊的工作空间配置丢失,按照默认的设置)


请 按步骤解决!如果该步骤解决问题了,别再执行下面的步骤!

请注意我的提醒: A 代码是对的 B 该步骤解决问题了,别再执行下面的步骤!

计划。。。

计划一下寒假怎么过吧。。。

十三号考完。。十四号应该能到家。。。。回家以为先让电脑能上网了。。

找朋友同学玩几天。。放松一下。。还有吃老妈做的排骨。。哀。。在学校受罪。吃不到老妈做的排骨。。半年了。。十一月底回家是因为得肠炎了。。还回去输了几天液。没吃到好吃的。。寒假回家一定要补回来。。。

寒假回来了一定要做一个像样的东东出来。。。有目标了。。做一匹木马。。哈哈。。从接触黑客开始就幻想什么时候能开发出来属于自己的木马。。直到现在才有了条件,才有了这资本,这条件和资本就是时间!现在,我属于什么都没有的穷光蛋。。只有时间!呵呵。。做出来一个像样的木马应该不会太难。。心里面已经有了框架。。

木马≈远程控制软件

快考试了。。精确的说还有四十八个小时就要考试了。。两天的时间。。希望大家都顺利通过!

当开学的时候,我要再发一篇日志。。庆祝我的木马大功告成。。朋友们祝我好运吧。。

得到本机所有IP的两种方法[转自CSDN]

最近由于需要做一个穿透网吧管理软件对交换机和路由器限制功能。 我给本机设置了 10 个IP地址,用于接收硬件传来的数据。
我需要得到本机所有的 IP 地址.  
现在整理一下,已备后用。

bool GetLocalALL_IPAddress( CStringArray & strArrayIP )

{

    CHAR szHostName[100];

    struct addrinfo *res ;

    struct addrinfo *next = NULL ;
    WORD version;

    WSADATA data;
    version = MAKEWORD(0x02, 0x02);
    ::WSAStartup( version , &data );



    if ( SOCKET_ERROR == ::gethostname( szHostName, sizeof( szHostName ) ) )

    {

        ::WSACleanup();
        return false ;

    }
   //   getaddrinfo 这个API 在window 2000 的 ws2_32.dll 中找不到入口点,没有导出这个函数
    if ( 0 != getaddrinfo( szHostName, NULL , NULL , &res ) )

    {

        ::WSACleanup();
        return false ;

    }

    /**//*

    考虑到兼容多个协议的数据结构, MS 没有把下面的结构体 直接写成 struct sockaddr_in .
    struct sockaddr

    {

    u_short    sa_family;

    char       sa_data[14];

    };  
    struct sockaddr_in

    {

    short   sin_family;

    u_short sin_port;

    struct in_addr sin_addr;

    char    sin_zero[8];

    };
    */
    next = res ;
    do

    {

        strArrayIP.Add( inet_ntoa( ( (sockaddr_in *)(next->ai_addr) )->sin_addr ) );
        next = next->ai_next ;
    }while ( next != NULL ) ;
    ::WSACleanup();
    return true ;

}

bool help::Network::GetALL_IPAddress2( CStringArray & strArrayIP )

{

bool bRet ;

CHAR szHostName[100];

struct addrinfo *res ;

struct addrinfo *next = NULL ;

WORD version;

WSADATA data;

version = MAKEWORD(0x02, 0x02);



::WSAStartup( version , &data );

if ( SOCKET_ERROR == ::gethostname( szHostName, sizeof( szHostName ) ) )

{

   ::WSACleanup();

   return false ;

}

struct hostent * pHostent = gethostbyname( szHostName );


if ( pHostent == NULL )

{

   ::WSACleanup();

   return false;

}




int i=0;

while ( pHostent->h_addr_list[i] != NULL )

{

   in_addr in;

   in.S_un.S_addr = *(DWORD* )(pHostent->h_addr_list[i] );

   strArrayIP.Add( inet_ntoa(in) );



   i++ ;

}



::WSACleanup();

return true ;

}

VC中使用ListCtrl经验总结

VC中使用ListCtrl经验总结


  ListCtrl在工作中,常常用到,也常常看到大家发帖问怎么用这个控件,

故总结了一下自己的使用经验,以供参考使用。

  先注明一下,这里,我们用m_listctrl来表示一个CListCtrl的类对象,

然后这里我们的ListCtrl都是report形式,至于其他的如什么大图标,小图标

的暂时不讲,毕竟report是大众话的使用。其次,我们这里用条款一,条款二

来描述第一点,第二点,这个是参照《Effective C++》的叫法,俺觉得这么

叫比较COOL :)

 条款一:设置ListCtrl的风格

 在CSDN上常常看到有人问怎么设置风格的,他们ListCtrl的样子是一个列表

,有横条和竖条分界线,然后选中一行,要整一行都选中,而不是只有某一列

被选中,等等,这里给一个比较全面的设置方法。

//获得原有风格

DWORD dwStyle = ::GetWindowLong(m_listctrl.m_hWnd, GWL_STYLE);

dwStyle &= ~(LVS_TYPEMASK);

dwStyle &= ~(LVS_EDITLABELS);

//设置新风格

     SetWindowLong(m_listctrl.m_hWnd, GWL_STYLE,

dwStyle,|LVS_REPORT|LVS_NOLABELWRAP|LVS_SHOWSELALWAYS);


//设置扩展风格

DWORD styles =

LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES;

ListView_SetExtendedListViewStyleEx(m_listctrl.m_hWnd, styles,

styles );

其中LVS_EX_FULLROWSELECT 就是前面说得整行选中

LVS_EX_GRIDLINES 网格线(只适用与report风格的listctrl)

LVS_EX_CHECKBOXES 前面加个checkbox

pListCtrl->SetExtendedStyle(   m_listctrl.GetExtendedStyle()

|LVS_EX_SUBITEMIMAGES);


这也是一个很重要的属性,这样的话,可以在列表中加ICON,记得windows的

任务管理器吗,你想做得那样,这个属性也要加哦,这个我以后会讲的~

条款二:加入列头

  这是一个比较实质的东西,给列表框分列,然后加上列头

  代码说话,来了

  TCHAR rgtsz[2][10] = {_T(“列头1″), _T(“列头2″)};


LV_COLUMN lvcolumn;

CRect rect;

m_listctrl.GetWindowRect(&rect);

for(int i=0;i<2;i++)

{

    lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT

               | LVCF_WIDTH | LVCF_ORDER;

    lvcolumn.fmt = LVCFMT_LEFT;

    lvcolumn.pszText = rgtsz[i];

  lvcolumn.iSubItem = i;

    lvcolumn.iOrder = i;

  if(i==0)

    {

       lvcolumn.cx = rect.Width()*3/5 ;

  }

  else

      lvcolumn.cx = rect.Width()*2/5;

       

   m_listctrl.InsertColumn(i, &lvcolumn);

 }

这是插入两列的做法,你要插入20列??随便你,依样画葫芦~~

 lvcolumn.mask 中那个mask可以有各种属性,具体去看msdn吧,


条款三:把记录,插入列表框中

 int nIndex = m_listctrl.GetItemCount();

   LV_ITEM    lvitemAdd = {0};

   lvitemAdd.mask = LVIF_TEXT;

   lvitemAdd.iItem = nIndex ;

   lvitemAdd.iSubItem = 0;

   lvitemAdd.pszText =_T(“毛毛1″);;

  

   if (m_listctrl.InsertItem(&lvitemAdd) != -1)

   {

    LV_ITEM lvitem = {0};

    lvitem.mask = LVIF_TEXT;

    lvitem.iItem = nIndex ;

    lvitem.iSubItem = 1;


    lvitem.pszText =_T(“毛毛2″);

    m_listctrl.SetItem(&lvitem);

   

   }

nIndex 是当前的行数,然后把新的一行,插在最下面,


条款四:给列表中插入图标

 在report格式中,也能插入图标

 继续代码说话

 m_image是个CImageList对象

 m_image.Create(16,16, TRUE|ILC_COLOR24, 3, 1);

m_listctrl.SetImageList(&m_image,LVSIL_SMALL);

然后调用CImageList的成员函数int CImageList::Add( HICON hIcon );

把ICON插入到imagelist,

 然后在插入记录的时候

 lvitemAdd.mask = LVIF_TEXT; -》 lvitemAdd.mask =

LVIF_TEXT|LVIF_IMAGE

 然后添加一个lvitemAdd.iImage = n;

 这个n是imagelist中的序号,表示是具体的哪一个图标,list么,呵呵


条款五: 插入记录时使用额外的信息,lParam 的使用

   有时候,你想对于某一行,加入一些额外的信息,那么就可以使用这个

lParam

  msdn是这么描述的Specifies the 32-bit value of the item

  我上次是为了在某一行加入一个信息,窗口句柄,然后是这么加的,

  int nIndex = m_listctrl.GetItemCount();

   LV_ITEM    lvitemAdd = {0};

   lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;

   lvitemAdd.iItem = nIndex ;

   lvitemAdd.iSubItem = 0;

   lvitemAdd.pszText =_T(“毛毛1″);;

   lvitemAdd.iImage = n;

   lvitemAdd.lParam = (LPARAM)hwnd;(某个窗口的窗口句柄)


   if (m_listctrl.InsertItem(&lvitemAdd) != -1)

   {

    LV_ITEM lvitem = {0};

    lvitem.mask = LVIF_TEXT;

    lvitem.iItem = nIndex ;

    lvitem.iSubItem = 1;


    lvitem.pszText =_T(“毛毛2″);

    m_listctrl.SetItem(&lvitem);

   

   }

ok,这是一个比较全的例子的,又插ICON,又使用PARAM的

条款六 : 点击列表框,获取选中行信息

  响应NM_CLICK消息,如果你有MSDN,可以看到,有专门关于listview的

NM_CLICK的介绍

void CMyDlg::OnItemClick(NMHDR* pNMHDR, LRESULT* pResult)

{

// TODO: Add your control notification handler code here

int nItem = -1;


LPNMITEMACTIVATE lpNMItemActivate = (LPNMITEMACTIVATE)pNMHDR;

if(lpNMItemActivate != NULL)

{

      nItem = lpNMItemActivate->iItem;

}

}

现在nItem就是点击选中那行的index了,有了index,获取那行的信息还难吗



懒汉说:难,因为你还没讲,晕,那就继续说


条款七: 根据行的index,获取该行的信息

 直接上代码吧

 LV_ITEM lvitem = {0};

    lvitem.iItem = nIndex;

    lvitem.iSubItem = 0;

    lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;

m_listctrl.GetItem(&lvitem)

这样,就把nindex,第一列的信息取出来了,包括刚才我们加入的ICON,和那个

额外信息(窗口句柄),

比如我要获取窗口句柄,就可以hwnd = (HWND)lvitem.lParam;

mask 用来指明你想获取那些信息

具体可以查msdn中LVITEM Structure的定义和CListCtrl::GetItem


条款八:用程序选中某一行,使之选中

选中之 

m_listctrl.SetItemState

(nIndex,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);

不选中,取消选中之

m_listctrl.SetItemState(nIndex,0,LVIS_SELECTED|LVIS_FOCUSED);


条款九:获取当前所有选中的行(多选)

  这个,俺就比较懒了,抄msdn的代码吧,反正很简单

  

Example

// CListCtrl* pListCtrl = (CListCtrl*) GetDlgItem

(IDC_YOURLISTCONTROL);

ASSERT(pListCtrl != NULL);

POSITION pos = pList->GetFirstSelectedItemPosition();

if (pos == NULL)

    TRACE0(“No items were selected!n”);

else

{

   while (pos)

   {

      int nItem = pList->GetNextSelectedItem(pos);

      TRACE1(“Item %d was selected!n”, nItem);

      // you could do your own processing on nItem here

   }

}


条款十:删除条款九中选中的行

  这个相对前面九个条款是比较麻烦的,因为如果你要删除多行的话。往往要出错

  比如,我现在要删除第0行和第1行(列表的行序列是从0开始的)

  那么好啊。我来删了

  m_listctrl.DeleteItem(0)

         m_listctrl.DeleteItem(1)

  恭喜你,错了,我好开心啊 :)

  因为你删除第0行以后,下面的行会往上移,那么原来的第1行就变成了第0行,那么你再

m_listctrl.DeleteItem(1),那么删除的是原来的第2行,真麻烦,

   所以,只有从下往上删,才是安全的,先删的,不会影响后面的操作,

    m_listctrl.DeleteItem(1)

         m_listctrl.DeleteItem(0)

  但有时候,我们也不知道要删除哪些行,只知道要删除选中的那些行,像条款九中的那些

   如果我们还是用

   

POSITION pos = m_listctrl.GetFirstSelectedItemPosition();

if (pos == NULL)

    TRACE0(“No items were selected!n”);

else

{

   while (pos)

   {

      int nItem = m_listctrl.GetNextSelectedItem(pos);

    

 m_listctrl.DeleteItem(nItem );

   }

}

你就等着犯错吧!

这时候我们就要鄙视一下微软了,为虾米木有GetLastselectedItemPosition 和GetPrevSelectedItem

多写一对成员函数会死啊 :(

 没办法,办法自己想,这里有个笨办法

 POSITION   sSelPos = NULL;

while(sSelPos = m_listctrl.GetFirstSelectedItemPosition())

{

         int nSelItem = -1;

          nSelItem = m_listctrl.GetNextSelectedItem(sSelPos);

          if(nSelItem >= 0 && nSelItem<m_listctrl.GetItemCount())

        {

              好了,这个nSelItem 就是我们要的DD

       }

}

GetNextSelectedItem这个函数,看msdn的用法,其实是返回第一个的index,然后走到下一个选中的行去,所以这么做也是安全的


,在实际中,俺也是这么做的,测试也通过,没问题的

当然,还有个办法,先通过GetFirstSelectedItemPosition和GetNextSelectedItem

来获取所有的选中行的index,然后把这些index放到一个数组里,然后再从下往上删

唉真麻烦啊,还要不定数组,不说用new在堆上开吧,那么一个vector总是要的吧,麻烦啊

所以我暂时是用上述的办法来删除,也供大家参考,希望能找到更好的办法。

关于select和WSASelect[转自CSDN]

与socket有关的一些函数介绍

1、读取当前错误值:每次发生错误时,如果要对具体问题进行处理,那么就应该调用这个函数取得错误代码。

int  WSAGetLastError(void );
      #define h_errno   WSAGetLastError()

错误值请自己阅读Winsock2.h。


2、将主机的unsigned long值转换为网络字节顺序(32位):为什么要这样做呢?因为不同的计算机使用不同的字节顺序存储数据。因此任何从Winsock函数对IP地址和端口号的引用和传给Winsock函数的IP地址和端口号均时按照网络顺序组织的。

u_long  htonl(u_long hostlong);
      举例:htonl(0)=0
      htonl(80)= 1342177280

3、将unsigned long数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。

u_long  ntohl(u_long netlong);
      举例:ntohl(0)=0
      ntohl(1342177280)= 80

4、将主机的unsigned short值转换为网络字节顺序(16位):原因同2:

u_short  htons(u_short hostshort);
      举例:htonl(0)=0
      htonl(80)= 20480

5、将unsigned short数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。

u_short  ntohs(u_short netshort);
      举例:ntohs(0)=0
      ntohsl(20480)= 80

6、将用点分割的IP地址转换位一个in_addr结构的地址,这个结构的定义见笔记(一),实际上就是一个unsigned long值。计算机内部处理IP地址可是不认识如192.1.8.84之类的数据。

unsigned long  inet_addr( const char FAR * cp );
      举例:inet_addr("192.1.8.84")=1409810880
      inet_addr("127.0.0.1")= 16777343

如果发生错误,函数返回INADDR_NONE值。


7、将网络地址转换位用点分割的IP地址,是上面函数的逆函数。

char FAR *  inet_ntoa( struct in_addr in );
      举例:char * ipaddr=NULL;
      char addr[20];
      in_addr inaddr;
      inaddr. s_addr=16777343;
      ipaddr= inet_ntoa(inaddr);
      strcpy(addr,ipaddr);

这样addr的值就变为127.0.0.1。

注意意不要修改返回值或者进行释放动作。如果函数失败就会返回NULL值。


8、获取套接字的本地地址结构:

int  getsockname(SOCKET s, struct sockaddr FAR * name, int FAR * namelen );
      s为套接字
      name为函数调用后获得的地址值
      namelen为缓冲区的大小。

9、获取与套接字相连的端地址结构:

int  getpeername(SOCKET s, struct sockaddr FAR * name, int FAR * namelen );
      s为套接字
      name为函数调用后获得的端地址值
      namelen为缓冲区的大小。

10、获取计算机名:

int  gethostname( char FAR * name, int namelen );
      name是存放计算机名的缓冲区
      namelen是缓冲区的大小
      用法:
      char szName[255];
      memset(szName,0,255);
      if(gethostname(szName,255)==SOCKET_ERROR)
      {
        //错误处理
      }
      返回值为:szNmae="xiaojin"

11、根据计算机名获取主机地址:

struct hostent FAR *  gethostbyname( const char FAR * name );

      name为计算机名。
      用法:
      hostent * host;
      char* ip;
      host= gethostbyname("xiaojin");
      if(host-&gt;h_addr_list[0])
      {
       struct in_addr addr;
       memmove(&amp;addr, host-&gt;h_addr_list[0],4);
       //获得标准IP地址
       ip=inet_ ntoa (addr);
      }

      返回值为:hostent-&gt;h_name="xiaojin"
          hostent-&gt;h_addrtype=2    //AF_INET
          hostent-&gt;length=4
          ip="127.0.0.1"

Winsock 的I/O操作:


1、 两种I/O模式

  • 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序。套接字 默认为阻塞模式。可以通过多线程技术进行处理。
  • 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权。这种模式使用 起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误。但功能强大。

为了解决这个问题,提出了进行I/O操作的一些I/O模型,下面介绍最常见的三种:


2、select模型:


  通过调用select函数可以确定一个或多个套接字的状态,判断套接字上是否有数据,或

者能否向一个套接字写入数据。

int  select( int nfds, fd_set FAR * readfds, fd_set FAR * writefds,
      fd_set FAR *exceptfds, const struct timeval FAR * timeout );

◆先来看看涉及到的结构的定义:

a、 d_set结构:

#define FD_SETSIZE 64?
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;

fd_count为已设定socket的数量

fd_array为socket列表,FD_SETSIZE为最大socket数量,建议不小于64。这是微软建

议的。


B、timeval结构:

struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};

tv_sec为时间的秒值。

tv_usec为时间的毫秒值。

这个结构主要是设置select()函数的等待值,如果将该结构设置为(0,0),则select()函数

会立即返回。


◆再来看看select函数各参数的作用:

  1. nfds:没有任何用处,主要用来进行系统兼容用,一般设置为0。
  2. readfds:等待可读性检查的套接字组。
  3. writefds;等待可写性检查的套接字组。
  4. exceptfds:等待错误检查的套接字组。
  5. timeout:超时时间。
  6. 函数失败的返回值:调用失败返回SOCKET_ERROR,超时返回0。

readfds、writefds、exceptfds三个变量至少有一个不为空,同时这个不为空的套接字组

种至少有一个socket,道理很简单,否则要select干什么呢。 举例:测试一个套接字是否可读:

fd_set fdread;
//FD_ZERO定义
// #define FD_ZERO(set) (((fd_set FAR *)(set))-&gt;fd_count=0)
FD_ZERO(&amp;fdread);
FD_SET(s,&amp;fdread); //加入套接字,详细定义请看winsock2.h
if(select(0,%fdread,NULL,NULL,NULL)&gt;0
{
 //成功
 if(FD_ISSET(s,&amp;fread) //是否存在fread中,详细定义请看winsock2.h
 {
  //是可读的
 }
}

◆I/O操作函数:主要用于获取与套接字相关的操作参数。

int  ioctlsocket(SOCKET s, long cmd, u_long FAR * argp );

s为I/O操作的套接字。

cmd为对套接字的操作命令。

argp为命令所带参数的指针。


常见的命令:

//确定套接字自动读入的数据量
#define FIONREAD _IOR(''''f'''', 127, u_long) /* get # bytes to read */
//允许或禁止套接字的非阻塞模式,允许为非0,禁止为0
#define FIONBIO _IOW(''''f'''', 126, u_long) /* set/clear non-blocking i/o */
//确定是否所有带外数据都已被读入
#define SIOCATMARK _IOR(''''s'''', 7, u_long) /* at oob mark? */

3、WSAAsynSelect模型:

WSAAsynSelect模型也是一个常用的异步I/O模型。应用程序可以在一个套接字上接收以

WINDOWS消息为基础的网络事件通知。该模型的实现方法是通过调用WSAAsynSelect函

数 自动将套接字设置为非阻塞模式,并向WINDOWS注册一个或多个网络时间,并提供一

个通知时使用的窗口句柄。当注册的事件发生时,对应的窗口将收到一个基于消息的通知。

int  WSAAsyncSelect( SOCKET s, HWND hWnd, u_int wMsg, long lEvent);

s为需要事件通知的套接字

hWnd为接收消息的窗口句柄

wMsg为要接收的消息

lEvent为掩码,指定应用程序感兴趣的网络事件组合,主要如下:

#define FD_READ_BIT 0
#define FD_READ (1 &lt;&lt; FD_READ_BIT)
#define FD_WRITE_BIT 1
#define FD_WRITE (1 &lt;&lt; FD_WRITE_BIT)
#define FD_OOB_BIT 2
#define FD_OOB (1 &lt;&lt; FD_OOB_BIT)
#define FD_ACCEPT_BIT 3
#define FD_ACCEPT (1 &lt;&lt; FD_ACCEPT_BIT)
#define FD_CONNECT_BIT 4
#define FD_CONNECT (1 &lt;&lt; FD_CONNECT_BIT)
#define FD_CLOSE_BIT 5
#define FD_CLOSE (1 &lt;&lt; FD_CLOSE_BIT)

用法:要接收读写通知:

int nResult= WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE);
if(nResult==SOCKET_ERROR)
{
 //错误处理
}

取消通知:

int nResult= WSAAsyncSelect(s,hWnd,0,0);

当应用程序窗口hWnd收到消息时,wMsg.wParam参数标识了套接字,lParam的低字标明

了网络事件,高字则包含错误代码。


4、WSAEventSelect模型

WSAEventSelect模型类似WSAAsynSelect模型,但最主要的区别是网络事件发生时会被发

送到一个事件对象句柄,而不是发送到一个窗口。


使用步骤如下:

a、 创建事件对象来接收网络事件:

#define WSAEVENT HANDLE
#define LPWSAEVENT LPHANDLE
WSAEVENT WSACreateEvent( void );

该函数的返回值为一个事件对象句柄,它具有两种工作状态:已传信(signaled)和未传信

(nonsignaled)以及两种工作模式:人工重设(manual reset)和自动重设(auto reset)。默认未

未传信的工作状态和人工重设模式。


b、将事件对象与套接字关联,同时注册事件,使事件对象的工作状态从未传信转变未

已传信。

int  WSAEventSelect( SOCKET s,WSAEVENT hEventObject,long lNetworkEvents );

s为套接字

hEventObject为刚才创建的事件对象句柄

lNetworkEvents为掩码,定义如上面所述


c、I/O处理后,设置事件对象为未传信

BOOL WSAResetEvent( WSAEVENT hEvent );

Hevent为事件对象


成功返回TRUE,失败返回FALSE。


d、等待网络事件来触发事件句柄的工作状态:

DWORD WSAWaitForMultipleEvents( DWORD cEvents,
const WSAEVENT FAR * lphEvents, BOOL fWaitAll,
DWORD dwTimeout, BOOL fAlertable );

lpEvent为事件句柄数组的指针

cEvent为为事件句柄的数目,其最大值为WSA_MAXIMUM_WAIT_EVENTS

fWaitAll指定等待类型:TRUE:当lphEvent数组重所有事件对象同时有信号时返回;

FALSE:任一事件有信号就返回。

dwTimeout为等待超时(毫秒)

fAlertable为指定函数返回时是否执行完成例程


对事件数组中的事件进行引用时,应该用WSAWaitForMultipleEvents的返回值,减去

预声明值WSA_WAIT_EVENT_0,得到具体的引用值。例如:

nIndex=WSAWaitForMultipleEvents(…);
MyEvent=EventArray[Index- WSA_WAIT_EVENT_0];

e、判断网络事件类型:

int WSAEnumNetworkEvents( SOCKET s,
WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents );

s为套接字

hEventObject为需要重设的事件对象

lpNetworkEvents为记录网络事件和错误代码,其结构定义如下:

typedef struct _WSANETWORKEVENTS {
 long lNetworkEvents;
 int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;

f、关闭事件对象句柄:

BOOL WSACloseEvent(WSAEVENT hEvent);

调用成功返回TRUE,否则返回FALSE。

常用数据类型转换

刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解,本文将介绍一些常用数据类型的使用。


我们先定义一些常见类型变量借以说明


int i = 100;

long l = 2001;

float f=300.2;

double d=12345.119;

char username[]=”程佩君”;

char temp[200];

char *buf;

CString str;

_variant_t v1;

_bstr_t v2;


一、其它数据类型转换为字符串



短整型(int)

itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制

itoa(i,temp,2); ///按二进制方式转换

长整型(long)

ltoa(l,temp,10);

浮点数(float,double)

用fcvt可以完成转换,这是MSDN中的例子:

int decimal, sign;

char *buffer;

double source = 3.1415926535;

buffer = _fcvt( source, 7, &decimal, &sign );

运行结果:source: 3.1415926535 buffer: ‘31415927’ decimal: 1 sign: 0

decimal表示小数点的位置,sign表示符号:0为正数,1为负数

CString变量

str = “2008北京奥运”;

buf = (LPSTR)(LPCTSTR)str;

BSTR变量

BSTR bstrValue = ::SysAllocString(L”程序员”);

char * buf = _com_util::ConvertBSTRToString(bstrValue);

SysFreeString(bstrValue);

AfxMessageBox(buf);

delete(buf);

CComBSTR变量

CComBSTR bstrVar(“test”);

char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str);

AfxMessageBox(buf);

delete(buf);


_bstr_t变量

_bstr_t类型是对BSTR的封装,因为已经重载了=操作符,所以很容易使用

_bstr_t bstrVar(“test”);

const char *buf = bstrVar;///不要修改buf中的内容

AfxMessageBox(buf);



通用方法(针对非COM数据类型)

用sprintf完成转换

char buffer[200];

char c = ‘1’;

int i = 35;

long j = 1000;

float f = 1.7320534f;

sprintf( buffer, “%c”,c);

sprintf( buffer, “%d”,i);

sprintf( buffer, “%d”,j);

sprintf( buffer, “%f”,f);


二、字符串转换为其它数据类型

strcpy(temp,”123″);


短整型(int)

i = atoi(temp);

长整型(long)

l = atol(temp);

浮点(double)

d = atof(temp);

CString变量

CString name = temp;

BSTR变量

BSTR bstrValue = ::SysAllocString(L”程序员”);

…///完成对bstrValue的使用

SysFreeString(bstrValue);


CComBSTR变量

CComBSTR类型变量可以直接赋值

CComBSTR bstrVar1(“test”);

CComBSTR bstrVar2(temp);


_bstr_t变量

_bstr_t类型的变量可以直接赋值

_bstr_t bstrVar1(“test”);

_bstr_t bstrVar2(temp);



三、其它数据类型转换到CString

使用CString的成员函数Format来转换,例如:



整数(int)

str.Format(“%d”,i);

浮点数(float)

str.Format(“%f”,i);

字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值

str = username;

对于Format所不支持的数据类型,可以通过上面所说的关于其它数据类型转化到char *的方法先转到char *,然后赋值给CString变量。


四、BSTR、_bstr_t与CComBSTR



CComBSTR 是ATL对BSTR的封装,_bstr_t是C++对BSTR的封装,BSTR是32位指针,但并不直接指向字串的缓冲区。

char *转换到BSTR可以这样:

BSTR b=_com_util::ConvertStringToBSTR(“数据”);///使用前需要加上comutil.h和comsupp.lib

SysFreeString(bstrValue);

反之可以使用

char *p=_com_util::ConvertBSTRToString(b);

delete p;

具体可以参考一,二段落里的具体说明。


CComBSTR与_bstr_t对大量的操作符进行了重载,可以直接进行=,!=,==等操作,所以使用非常方便。

特别是_bstr_t,建议大家使用它。



五、VARIANT 、_variant_t 与 COleVariant



VARIANT的结构可以参考头文件VC98IncludeOAIDL.H中关于结构体tagVARIANT的定义。

对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:

VARIANT va;

int a=2001;

va.vt=VT_I4;///指明整型数据

va.lVal=a; ///赋值


对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:


Byte bVal; // VT_UI1.

Short iVal; // VT_I2.

long lVal; // VT_I4.

float fltVal; // VT_R4.

double dblVal; // VT_R8.

VARIANT_BOOL boolVal; // VT_BOOL.

SCODE scode; // VT_ERROR.

CY cyVal; // VT_CY.

DATE date; // VT_DATE.

BSTR bstrVal; // VT_BSTR.

DECIMAL FAR* pdecVal // VT_BYREF|VT_DECIMAL.

IUnknown FAR* punkVal; // VT_UNKNOWN.

IDispatch FAR* pdispVal; // VT_DISPATCH.

SAFEARRAY FAR* parray; // VT_ARRAY|*.

Byte FAR* pbVal; // VT_BYREF|VT_UI1.

short FAR* piVal; // VT_BYREF|VT_I2.

long FAR* plVal; // VT_BYREF|VT_I4.

float FAR* pfltVal; // VT_BYREF|VT_R4.

double FAR* pdblVal; // VT_BYREF|VT_R8.

VARIANT_BOOL FAR* pboolVal; // VT_BYREF|VT_BOOL.

SCODE FAR* pscode; // VT_BYREF|VT_ERROR.

CY FAR* pcyVal; // VT_BYREF|VT_CY.

DATE FAR* pdate; // VT_BYREF|VT_DATE.

BSTR FAR* pbstrVal; // VT_BYREF|VT_BSTR.

IUnknown FAR* FAR* ppunkVal; // VT_BYREF|VT_UNKNOWN.

IDispatch FAR* FAR* ppdispVal; // VT_BYREF|VT_DISPATCH.

SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*.

VARIANT FAR* pvarVal; // VT_BYREF|VT_VARIANT.

void FAR* byref; // Generic ByRef.

char cVal; // VT_I1.

unsigned short uiVal; // VT_UI2.

unsigned long ulVal; // VT_UI4.

int intVal; // VT_INT.

unsigned int uintVal; // VT_UINT.

char FAR * pcVal; // VT_BYREF|VT_I1.

unsigned short FAR * puiVal; // VT_BYREF|VT_UI2.

unsigned long FAR * pulVal; // VT_BYREF|VT_UI4.

int FAR * pintVal; // VT_BYREF|VT_INT.

unsigned int FAR * puintVal; //VT_BYREF|VT_UINT.



_variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。

使用时需加上#include <comdef.h>

例如:

long l=222;

ing i=100;

_variant_t lVal(l);

lVal = (long)i;



COleVariant的使用与_variant_t的方法基本一样,请参考如下例子:

COleVariant v3 = “字符串”, v4 = (long)1999;

CString str =(BSTR)v3.pbstrVal;

long i = v4.lVal;



六、其它一些COM数据类型


根据ProgID得到CLSID

HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);

CLSID clsid;

CLSIDFromProgID( L”MAPI.Folder”,&clsid);


根据CLSID得到ProgID

WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID);

例如我们已经定义了 CLSID_IApplication,下面的代码得到ProgID

LPOLESTR pProgID = 0;

ProgIDFromCLSID( CLSID_IApplication,&pProgID);

…///可以使用pProgID

CoTaskMemFree(pProgID);//不要忘记释放


七、ANSI与Unicode

Unicode称为宽字符型字串,COM里使用的都是Unicode字符串。


将ANSI转换到Unicode

(1)通过L这个宏来实现,例如: CLSIDFromProgID( L”MAPI.Folder”,&clsid);

(2)通过MultiByteToWideChar函数实现转换,例如:

char *szProgID = “MAPI.Folder”;

WCHAR szWideProgID[128];

CLSID clsid;

long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));

szWideProgID[lLen] = ‘';

(3)通过A2W宏来实现,例如:

USES_CONVERSION;

CLSIDFromProgID( A2W(szProgID),&clsid);

将Unicode转换到ANSI

(1)使用WideCharToMultiByte,例如:

// 假设已经有了一个Unicode 串 wszSomeString…

char szANSIString [MAX_PATH];

WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL );

(2)使用W2A宏来实现,例如:

USES_CONVERSION;

pTemp=W2A(wszSomeString);

八、其它


对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如:

LPARAM lParam;

WORD loValue = LOWORD(lParam);///取低16位

WORD hiValue = HIWORD(lParam);///取高16位



对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:

WORD wValue;

BYTE loValue = LOBYTE(wValue);///取低8位

BYTE hiValue = HIBYTE(wValue);///取高8位



两个16位数据(WORD)合成32位数据(DWORD,LRESULT,LPARAM,或WPARAM)

LONG MAKELONG( WORD wLow, WORD wHigh );

WPARAM MAKEWPARAM( WORD wLow, WORD wHigh );

LPARAM MAKELPARAM( WORD wLow, WORD wHigh );

LRESULT MAKELRESULT( WORD wLow, WORD wHigh );



两个8位的数据(BYTE)合成16位的数据(WORD)

WORD MAKEWORD( BYTE bLow, BYTE bHigh );



从R(red),G(green),B(blue)三色得到COLORREF类型的颜色值

COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );

例如COLORREF bkcolor = RGB(0x22,0x98,0x34);



从COLORREF类型的颜色值得到RGB三个颜色值

BYTE Red = GetRValue(bkcolor); ///得到红颜色

BYTE Green = GetGValue(bkcolor); ///得到绿颜色

BYTE Blue = GetBValue(bkcolor); ///得到兰颜色



九、注意事项

假如需要使用到ConvertBSTRToString此类函数,需要加上头文件comutil.h,并在setting中加入comsupp.lib或者直接加上#pragma comment( lib, “comsupp.lib” )