1.VARIANT和SAFEARRAY数据类型是什么鬼?
我们在使用MSComm控件时,在发送与接收数据时都要用到VARIANT数据类型。此外,SAFEARRAY (COLeSafeArray)数据变量也可以用于处理接收到的数据。
VARIANT、_variant_t、COleVariant数据类型
VARIANT及由之而派生的COleVariant类主要用于在OLE自动化中传递数据。实际上,VARIANT也只不过是一个新定义的结构罢了!它的主要成员包括一个联合体及一个变量。该联合体由各种类型的数据成员构成,而该变量则用来指明联合体中目前其作用的数据类型。
对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,在对联合结构中相同数据类型的变量赋值。例如:
<span style="font-size:18px;font-weight: normal;">VARIANT vaData;//定义VARIANT类型变量
int a = 2001;
vaData.vt = VT_I4;//指明整型数据
vaData.lVal = a;//赋值</span>
而_vatiant_t是VATIANT的封装类,其赋值可以采用强制类型转换,其构造函数会自动处理这些数据类型。使用时需加上#include<comdef.h>
如:
<span style="font-size:18px;font-weight: normal;">long l = 222;
int i = 100;
_variant_t lVal(l);
lVal = (long)i;</span>
COleVariant的使用与_variant_t的方法基本一致,
如:
<span style="font-size:18px;font-weight: normal;">COleVariant v3 = _T("字符串"),v4 = (long)1999;
CString str = (BSTR)v3.pbstrVal;
long i = v4.lVal;</span>
SAFEARRAY(COleSafeArray)数据类型
这是一个安全数组,他可以根据系统环境自动调整其16位或32位的定义,并且不会被OLE改变。其实,我们完全没有必要了解他的具体定义,只要知道SAFEARRAY是另外的一个结构就好了。其中包括一个(void*)类型的指针pvData,其指向的内存就是存放有用数据的地方。简言之,从GetInput()函数返回的VARIANT类型变量中,找出parray指针,再从该指针指向的SAFEARRAY变量中找出pvData指针,就可以像访问数组一样取得所接收到的数据。
例一:把CString字符串类型数据转换成Variant类型数据从串口发送
如果是发送CString字符串,必须将其他类型转换为VARIANT类型变量才能发送。再上一个工程中点击打开链接,我们对发送的CString字符串做过强制转换。代码如下:
<span style="font-weight: normal;"><span style="font-size:18px;">void CSerialCommDlg::OnClickedButtonManualsend()
{
UpdateData(TRUE);
m_ctrlComm.put_Output(COleVariant(m_strEditTxData));//发送数据
}</span></span>
例二:把variant类型数据从串口读出并转换成CString字符串类型数据
在串口事件处理函数OnComm()中,应用SAFEARRAY(COleSafeArray)类型变量。代码如下:
<span style="font-size:18px;font-weight: normal;">void CSerialCommDlg::Oncomm()
{
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len, k;
BYTE rxdata[2048];
CString strtemp;
if (m_ctrlComm.get_CommEvent() == 2 ) //事件值为2表示接受缓冲区内有字符
{
variant_inp = m_ctrlComm.get_Input(); //读缓冲区
safearray_inp = variant_inp; //数据类型转换
</span><span style="font-weight: normal;"><span style="font-size:18px;"> len = safearray_inp.GetOneDimSize(); //得到有效数据长度
for (k = 0; k < len; k++)
safearray_inp.GetElement(&k, rxdata + k); //转换为BYTE型数组
for (k = 0; k < len; k++)
{
BYTE bt = *(char*)(rxdata + k); //字符型
strtemp.Format(_T("%c"),bt); //将字符送入临时变量中保存
//const char 与 const wchar_t不兼容
m_strEditRxData += strtemp;
}</span>
}
UpdateData(FALSE);
}</span>
2.MSComm是否可以脱离对话框而存在?
MSComm控件(几乎是所有的控件)都必须有一个可以寄身的对话框。而对话框工具栏中的图标是不能拖到视图(View)中去的,因此MSComm是离不开对话框的。当然,我们有另外一个变通的方法,做一个所谓的隐藏对话框,但是我们必须进行特殊的处理!
只需要我们在VIEW中的oncreate()函数中加上一些处理就好,并应用MSComm通信控件的Create()函数来创建。MSComm通信控件的Create()函数原型如下:
其中,UINT nID为该空间ID号。具体创建方法如下:
<span style="font-weight: normal;"><span style="font-size:18px;">m_MSComm.Create(NULL,0,CRect(0,0,0,0),this,IDC_MSCOMM1)</span></span>
3.如何发送ASCII码等于零和大于128的字符?
在C语言中,字符串型数据以0值作为结束标志,因此很多时候我都会对如何发送0值字符感到迷惑;同理,一旦ASCII值大于128,就不是我们能看到的常规字符了。其实这些数据的发送和接收也是比较简单的:将要发送的数据保存在有长度的有长度值的字符数组中。如下面的发送代码:
<span style="font-weight: normal;"><span style="font-size:18px;">//发送消息
void CSerialCommDlg::OnClickedButtonManualsend()
{
//UpdateData(TRUE);
//m_ctrlComm.put_Output(COleVariant(m_strEditTxData));//发送数据
unsigned char chData[8];
chData[0] = 0;
chData[1] = 1;
chData[2] = 13;
chData[3] = 12;
chData[4] = 0;
chData[5] = 10;
chData[6] = 156;
chData[7] = 255;
CByteArray binData; //定义字节数组
binData.RemoveAll();//清空binData
for (int i = 0; i < 8; i++)
binData.Add(chData[i]);
COleVariant var(binData);//将binData转换为Variant数据类型
m_ctrlComm.put_Output(var);//发送数据
}</span></span>
4.如何控制多个串口?
在使用MSComm控件时,1个MSComm控件只能同时对应一个串口。如果应用程序需要访问和控制多个串口,那么就必须使用多个MSComm控件。