碰到数据类型问题及解答

问题:COleVariant 

三、VARIANT、COleVariant 和_variant_t

  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:

struct tagVARIANT {
  VARTYPE vt;
  union {
   short iVal; // VT_I2.
   long lVal; // VT_I4.
   float fltVal; // VT_R4.
   double dblVal; // VT_R8.
   DATE date; // VT_DATE.
   BSTR bstrVal; // VT_BSTR.
   …
   short * piVal; // VT_BYREF|VT_I2.
   long * plVal; // VT_BYREF|VT_I4.
   float * pfltVal; // VT_BYREF|VT_R4.
   double * pdblVal; // VT_BYREF|VT_R8.
   DATE * pdate; // VT_BYREF|VT_DATE.
   BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
  };
};

  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:

VARIANT va;
:: VariantInit(&va); // 初始化
int a = 2002;
va.vt = VT_I4; // 指明long数据类型
va.lVal = a; // 赋值

  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:

  VariantInit —— 将变量初始化为VT_EMPTY;

  VariantClear —— 消除并初始化VARIANT;

  VariantChangeType —— 改变VARIANT的类型;

  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIA

COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:

COleVariant v1("This is a test"); // 直接构造
COleVariant v2 = "This is a test";
// 结果是VT_BSTR类型,值为"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// 结果是VT_I4类型,值为2002

  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:

  #include "comutil.h"

  #pragma comment( lib, "comsupp.lib" )
问题:COleSafeArray

VARIANT m_input1;
 COleSafeArray m_input2;
 LONG length,i;
 BYTE data[1024];
 CString str;
 //接收缓冲区内字符
 if(m_Comm.GetCommEvent()== 2)
 {
  m_comdata.Empty();
  //读取缓冲区内的数据
  m_input1=m_Comm.GetInput();
  //将VARIANT型变量转换为ColeSafeArray型变量
  m_input2=m_input1;
  //确定数据长度
  length=m_input2.GetOneDimSize();
  //将数据转换为BYTE型数组
  for(i=0;i< length;i++)
   m_input2.GetElement(&i,data+i);
   //将数组转换为CString型变量
  for(i=0;i< length;i++) {
   char a=* (char *)(data+i);
   str.Format(“%c",a);
   m_comdata += str;
  }
  /*在上面的程序中,先将VARIANT型变量
  转换为ColeSafeArray型变量,再将其转换为
  BYTE型数组,然后将数组转换为CString型变量,
  以满足不同的变量类型显示数据的需要

 

问题全面解读WM_NOTIFY

第三控件通知格式

  这个才真正涉及到我们要讲的内容,同时他也是最为灵活的一种格式。它的特征格式如下:WM_NOTIFY。
在WM_NOTIFY中,lParam中放的是一个称为NMHDR结构的指针。在wParam中放的则是控件的ID。

  NMHDR结构的由来

  NMHDR结构是很值得一提的,该结构包括有关制作该通知的控件的任何内容,而不受空间和类型的限制,他的来历也是很有意思的。

  在最初的windows3.x中,根本就不存在什么WM_NOTIFY,控件通知它们父窗口,如鼠标点击,控件背景绘制事件,通过发送一个消息到父窗口。简单的通知仅发送一个WM_COMMAND消息,包含一个通知码和一个在wParam中的控件ID及一个在lPraram中的控件句柄。这样一来,wParam和lParam就都被填充了,没有额外的空间来传递一些其它的消息,例如鼠标按下的位置和时间。

  为了克服这个困难,windows3.x就提出了一个比较低级的解决策略,那就是给一些消息添加一些附加消息,最为明显的就是控件自画用到的DRAWITEMSTRUCT。不知道大家对这个结构熟悉不,不过,如果你是老手,你应该非常清楚这个结构,这个结构包含了9个内容,几乎你需要控制的信息都给你提供了。为什么说它比较低级呢?因为不同的消息附加的内容不同,结果就是一盘散沙,非常混乱

  在win32中,MS又提出了一个更好的解决方案:引进NMHDR结构。这个结构的引进就是消息统一起来,利用它可以传递复杂的信息。这个结构的布局如下:

NMHDR
{
HWnd hWndFrom ; 相当于原WM_COMMAND传递方式的lParam
UINT idFrom ; 相当于原WM_COMMAND传递方式的wParam(low-order)
UINT code ; 相当于原WM_COMMAND传递方式的Notify Code(wParam"s high-order)
};

  对于这个结构的应用于WM_NOTIFY信息结构,结果WM_NOTIFY就变成了:

  A、无附加信息。结构变得很简单,就是一个NMHDR结构。
 
  B、有附加信息。定义一个大的结构,它的第一个元素就是NMHDR结构,它的后面放置附加信息。

WM_NOTIFY结构的好处

  除了上面我们所说的好处外,WN_NOTIFY还有自己的独特的好处:

  由于在大结构中,第一个成员为NMHDR,这样一来,我们就可以利用指向NMHDR的指针来传递结构地址,根据指针的特性,无论消息有没有附加信息,这个指针都适用,也能够很方便的进行强制转换。

  分析ON_NOTIFY

  类向导可以创建ON_NOTIFY消息映射入口并提供一个处理函数的框架,来处理 WM_NOTIFY类型的消息。ON_NOTIFY消息映射宏有如下语法.

   ON_NOTIFY(wNotifyCode,id,memberFxn)

  其中:wNotifyCode:要处理的通知消息通知码。比如上面我们提到的LVN_KEYDOWN;Id:控件标识ID;MemberFxn:处理此消息的成员函数。

  此成员函数有如下的原型声明:

   afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result);

  比如:假设你想成员函数OnKeydownList1处理ClistCtrl(标识ID=IDC_LIST1)的 LVN_KEYDOWN消息,你可以使用类向导添加如下的消息映射:

   ON_NOTIFY( LVN_KEYDOWN, IDC_LIST1, OnKeydownList1 )

  在上面的例子中,类向导提供如下函数:

   void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
    {
     LV_KEYDOWN* pLVKey= (LV_KEYDOWN*)pNMHDR;
     *pResult = 0;
     }

  这时类向导提供了一个适当类型的指针,你既可以通过pNMHDR,也可以通过 pLVKey来访问这个通知结构。

  ON_NOTIFY_RANGE

  有时我们可能需要为一组控件处理相同的WM_NOTIFY消息。这时需要使用ON_NOTIFY_RANGE而不是ON_NOTIFY。不过,很不幸的是,VC6的ClassWizard并不支持这个消息,所以我们必须手工添加。方法和一般的手工添加的消息一样,不过需要注意的是:

  (1)当你使用 ON_NOTIFY_RANGE时,你需要指定控件的ID范围.其消息映射入口及函数原型如下:

    ON_NOTIFY_RANGE( wNotifyCode, id, idLast, memberFxn )

  其中:wNotifyCode:消息通知码.比如:LVN_KEYDOWN。id: 第一控件的标识ID。
  
   idLast:最后一个控件的标识ID。(标识值一定要连续)memberFxn: 消息处理函数。

  (2)成员函数必须有如下原型申明:afx_msg void memberFxn( UINT id, NMHDR * pNotifyStruct, LRESULT * result );

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值