几年前我用VB开发了一个西门子PPI通信控件,由于VB开发的控件是标准的COM组件,所以想当然的认为VC、C#、Delphi等开发语言可以非常容易的使用。
前段时间由于该控件基于微软的MSCOMM控件,这个控件如果系统没有安装VB,单独注册好像很难成功,这害的一些没有装VB的用户,为了这个小控件必须安装一次VB,这实在是划算不来,所以直接用API串口函数进行了封装改进,这样不仅效率提高了,并且再也不需要MSCOMM控件了。
这一次,我不仅使该控件支持了浮点运算,并且在VC、C#(VB当然就不用多试了,以前就很好的支持)进行了兼容测试。
一试问题就来了,没有改进之前的控件,由于C#封装性能甚好,还能使用,唯一不足的是,控件方法中如果不要求返回的参数前面没有添加ByVal参数,在C#中就转换为 ref ***,害的你还得专门定义临时变量进行传参。
在VC中直接就不行,ReadData和WriteData等几个主要方法根本在VC中无法转换成对应函数,具体错误信息如下:
-
-
-
-
-
-
-
-
-
-
经过测试,最后发现VB函数中的byte和数组在VC中根本找不到合适的对应。
由于控件中又新添加了浮点数的支持,所以对参数接口又增加了一层复杂性。突然想到微软的MSCOMM控件各语言肯定都能很好的支持,它的接口参数是怎样的定义的。我在VB、VC、C#分别试了一下,VB中和input和Output属性的类型就是Variant类型,在VC中是VARIANT,在C#中是Object。用Variant还有个好处,就是各种类型的数据都可以传输,没有必要在另外添加接口函数了。
最后我定义的接口如下(主要接口):
- Public Function ReadData(ByVal lngAddr As Long, vData As Variant, Optional ByVal lngNum As Long = 1, Optional ByVal bytLen As PPILEN = PPI_B, Optional ByVal bytType As PPITYPE = PPI_V, Optional ByVal Addr As Long = 0) As Long
-
- Public Function WriteData(ByVal lngAddr As Long, ByVal vData As Variant, Optional ByVal lngNum As Long = 1, Optional ByVal bytLen As PPILEN = PPI_B, Optional ByVal bytType As PPITYPE = PPI_V, Optional ByVal Addr As Long = 0) As Long
-
-
-
在VC中对应的接口如下:
- long ReadData(long lngAddr, VARIANT* vData, long lngNum, long bytLen, long bytType, long Addr);
-
- long WriteData(long lngAddr, const VARIANT& vData, long lngNum, long bytLen, long bytType, long Addr);
在C#中的接口如下:
- public virtual int ReadData(int lngAddr, ref object vData);
-
- public virtual int ReadData(int lngAddr, ref object vData, int lngNum, PPILEN bytLen, PPITYPE bytType, int addr);
-
- public virtual int WriteData(int lngAddr, object vData);
-
- public virtual int WriteData(int lngAddr, object vData, int lngNum, PPILEN bytLen, PPITYPE bytType, int addr);
以为这样定义就万事大吉了,事后一试我又错了,在C#中没有任何问题(看了微软还是在C#上下了很大的功夫),在VC简单的定义一个VARIANT变量直接传递给控件,VB控件老是报错,根本无法使用。后来想为什么MSCOMM控件可以,我的控件不可以。天杀的MSCOMM肯定是VC开发的,而我的控件是VB开发的,VB和C#的包容性都很强,而VC却高高在上不肯屈就。
正一筹莫展准备放弃的时候,突然想到了以前用VC开发的OPC程序,上面有很多关于VARIANT的应用,一看就明白了,原来在VC中VARIANT的用法是有讲究的。
下面我就详细说一下控件同样的接口在不同语言中如何使用。
在VB中:
Private Sub cmdReadData_Click()
On Error GoTo ToExit '打开错误陷阱
'------------------------------------------------
- Dim i As Long
-
- Dim bytType As Byte
-
- Dim lngRet As Long
-
- Dim lngData() As Long
-
- Dim fData() As Single
-
- Dim vData As Variant
-
-
-
- Select Case cmbType.ListIndex
-
- Case 0: bytType = PPI_I
-
- Case 1: bytType = PPI_Q
-
- Case 2: bytType = PPI_M
-
- Case 3: bytType = PPI_V
-
- Case 4: bytType = PPI_S
-
- Case 5: bytType = PPI_SM
-
- End Select
-
-
-
- S7_PPI1.FixAddr = cmbNo.ListIndex + 1
-
- lngRet = S7_PPI1.ReadData(Val(txtAddr), vData, Val(cmbNum.Text), Val(cmbLen.ListIndex), Val(bytType))
-
-
-
- If lngRet = 0 Then
-
- txtData = ""
-
- If cmbLen.ListIndex = 3 Then
-
- fData = vData
-
- For i = 1 To Val(cmbNum.Text)
-
- txtData = txtData & Format(fData(i - 1), "0.00") & " "
-
- Next
-
- Else
-
- lngData = vData
-
- For i = 1 To Val(cmbNum.Text)
-
- txtData = txtData & Format(lngData(i - 1), "0") & " "
-
- Next
-
- End If
-
- Else
-
- txtData = "Error"
-
- End If
-
-
-
- '
-
- Exit Sub
-
- '
-
- ToExit:
-
- MsgBox Err.Description
-
- End Sub
-
- Private Sub cmdWriteData_Click()
-
- On Error GoTo ToExit '打开错误陷阱
-
- '
-
- Dim bytType As Byte
-
- Dim strData() As String
-
- Dim lngRet As Long
-
- Dim lngData(100) As Long
-
- Dim fData(100) As Single
-
- Dim i As Long
-
-
-
- Select Case cmbType.ListIndex
-
- Case 0: bytType = PPI_I
-
- Case 1: bytType = PPI_Q
-
- Case 2: bytType = PPI_M
-
- Case 3: bytType = PPI_V
-
- Case 4: bytType = PPI_S
-
- Case 5: bytType = PPI_SM
-
- End Select
-
-
-
- If Len(txtData) > 0 Then
-
- strData = Split(txtData, " ")
-
- If cmbLen.ListIndex = 3 Then
-
- For i = 0 To UBound(strData)
-
- fData(i) = Val(strData(i))
-
- Next
-
- lngRet = S7_PPI1.WriteData(Val(txtAddr), fData, UBound(strData) + 1, Val(cmbLen.ListIndex), Val(bytType), cmbNo.ListIndex + 1)
-
- Else
-
- For i = 0 To UBound(strData)
-
- lngData(i) = Val(strData(i))
-
- Next
-
- lngRet = S7_PPI1.WriteData(Val(txtAddr), lngData, UBound(strData) + 1, Val(cmbLen.ListIndex), Val(bytType), cmbNo.ListIndex + 1)
-
- End If
-
-
-
- If lngRet = 0 Then
-
- '
-
- Else
-
- txtData = "Error"
-
- End If
-
- End If
-
- '
-
- Exit Sub
-
- '
-
- ToExit:
-
- MsgBox Err.Description
-
- End Sub
-
-
-
在C#中:
-
-
-
-
-
-
-
-
-
-
- private void btnRead_Click(object sender, EventArgs e)
-
- {
-
- int intAddr = int.Parse(txtFixAddr.Text);
-
- object vData = new object();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PPIV2.PPITYPE DataType= PPIV2.PPITYPE.PPI_V;
-
- switch (cmbDataType.SelectedIndex)
-
- {
-
- case 0:
-
- DataType = PPIV2.PPITYPE.PPI_I;
-
- break;
-
- case 1:
-
- DataType = PPIV2.PPITYPE.PPI_Q;
-
- break;
-
- case 2:
-
- DataType = PPIV2.PPITYPE.PPI_M;
-
- break;
-
- case 3:
-
- DataType = PPIV2.PPITYPE.PPI_V;
-
- break;
-
- case 4:
-
- DataType = PPIV2.PPITYPE.PPI_S;
-
- break;
-
- case 5:
-
- DataType = PPIV2.PPITYPE.PPI_SM;
-
- break;
-
- }
-
- if (axS7_PPI1.ReadData(int.Parse(txtDataAddr.Text), ref vData, cmbLen.SelectedIndex+1 , (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr) == 0)
-
- {
-
- if (cmbDataMode.SelectedIndex == 3)
-
- {
-
- float[] fData = (float[])vData;
-
- txtData.Text = "";
-
- for (int i = 0; i < fData.Length; i++)
-
- {
-
- txtData.Text += fData[i].ToString("0.00") + " ";
-
- }
-
- }
-
- else
-
- {
-
- Int32[] intData = (Int32[])vData;
-
- txtData.Text = "";
-
- for (int i = 0; i < intData.Length; i++)
-
- {
-
- txtData.Text += intData[i].ToString() + " ";
-
- }
-
- }
-
- }
-
- else
-
- {
-
- txtData.Text = "ERROR";
-
- }
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- private void btnWrite_Click(object sender, EventArgs e)
-
- {
-
-
-
- int intAddr = int.Parse(txtFixAddr.Text);
-
- object vData = new object();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PPIV2.PPITYPE DataType = PPIV2.PPITYPE.PPI_V;
-
- switch (cmbDataType.SelectedIndex)
-
- {
-
- case 0:
-
- DataType = PPIV2.PPITYPE.PPI_I;
-
- break;
-
- case 1:
-
- DataType = PPIV2.PPITYPE.PPI_Q;
-
- break;
-
- case 2:
-
- DataType = PPIV2.PPITYPE.PPI_M;
-
- break;
-
- case 3:
-
- DataType = PPIV2.PPITYPE.PPI_V;
-
- break;
-
- case 4:
-
- DataType = PPIV2.PPITYPE.PPI_S;
-
- break;
-
- case 5:
-
- DataType = PPIV2.PPITYPE.PPI_SM;
-
- break;
-
- }
-
- long lngRet = 0;
-
- if (cmbDataMode.SelectedIndex == 3)
-
- {
-
- float[] fData = new float[100];
-
- fData[0] = float.Parse(txtData.Text);
-
- lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text), fData, 1, (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr);
-
- }
-
- else
-
- {
-
- Int32[] intData = new Int32[100];
-
- intData[0] = Int32.Parse(txtData.Text);
-
- lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text), intData, 1, (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr);
-
- }
-
- if (lngRet != 0)
-
- {
-
- txtData.Text = "ERROR";
-
- }
-
- }
-
-
-
在VC中:
-
-
- void CPPI_TestDlg::OnReadData()
-
- {
-
-
-
- long lngFixAddr=0,lngDataAddr=0;
-
- char strAddr[255];
-
- m_FixAddr.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%ld",&lngFixAddr);
-
-
-
- m_DataAddr.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%ld",&lngDataAddr);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- long DataType;
-
- switch (m_DataType.GetCurSel())
-
- {
-
- case 0:
-
- DataType=0x81;
-
- break;
-
- case 1:
-
- DataType=0x82;
-
- break;
-
- case 2:
-
- DataType=0x83;
-
- break;
-
- case 3:
-
- DataType=0x84;
-
- break;
-
- case 4:
-
- DataType=0x4;
-
- break;
-
- case 5:
-
- DataType=0x5;
-
- break;
-
- }
-
-
-
- long lngRet;
-
- VARIANT vData;
-
- VariantInit (&vData);
-
- if(m_DataMode.GetCurSel()==3)
-
- {
-
- vData.vt = VT_R4 | VT_ARRAY;
-
- vData.parray=SafeArrayCreateVector(VT_R4, 0, 255 );
-
- }
-
- else
-
- {
-
- vData.vt = VT_I4 | VT_ARRAY;
-
- vData.parray=SafeArrayCreateVector(VT_I4, 0, 255 );
-
- }
-
- lngRet=m_PPI.ReadData(lngDataAddr,&vData,m_DataNum.GetCurSel()+1,m_DataMode.GetCurSel(),DataType,lngFixAddr);
-
- if(lngRet==0)
-
- {
-
- CString strData;
-
- if(m_DataMode.GetCurSel()==3)
-
- {
-
- float *fData;
-
- SafeArrayAccessData(vData.parray, (void**)&fData );
-
- for(int i=0;i<m_DataNum.GetCurSel()+1;i++)
-
- {
-
- CString cData;
-
- cData.Format("%04.2f ",fData[i]);
-
- strData+= cData;
-
- }
-
- SafeArrayUnaccessData(vData.parray);
-
- }
-
- else
-
- {
-
- long *lngData;
-
- SafeArrayAccessData(vData.parray, (void**)&lngData );
-
- for(int i=0;i<m_DataNum.GetCurSel()+1;i++)
-
- {
-
- CString cData;
-
- cData.Format("%ld ",lngData[i]);
-
- strData+= cData;
-
- }
-
- SafeArrayUnaccessData(vData.parray);
-
- }
-
-
-
- m_Data.SetWindowText(strData);
-
- }
-
- else
-
- {
-
- m_Data.SetWindowText(_T("ERROR"));
-
- }
-
- SafeArrayUnaccessData(vData.parray);
-
- SafeArrayDestroy(vData.parray);
-
- VariantClear(&vData);
-
- }
-
-
-
-
-
- void CPPI_TestDlg::OnWrite()
-
- {
-
- long lngFixAddr=0,lngDataAddr=0;
-
- char strAddr[255];
-
- m_FixAddr.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%ld",&lngFixAddr);
-
-
-
- m_DataAddr.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%ld",&lngDataAddr);
-
-
-
- long DataType;
-
- switch (m_DataType.GetCurSel())
-
- {
-
- case 0:
-
- DataType=0x81;
-
- break;
-
- case 1:
-
- DataType=0x82;
-
- break;
-
- case 2:
-
- DataType=0x83;
-
- break;
-
- case 3:
-
- DataType=0x84;
-
- break;
-
- case 4:
-
- DataType=0x4;
-
- break;
-
- case 5:
-
- DataType=0x5;
-
- break;
-
- }
-
- long lngRet;
-
- VARIANT vData;
-
- VariantInit (&vData);
-
- if(m_DataMode.GetCurSel()==3)
-
- {
-
- vData.vt = VT_R4 | VT_ARRAY;
-
- vData.parray=SafeArrayCreateVector(VT_R4, 0, 255 );
-
-
-
- float *fDatas,fData;
-
- SafeArrayAccessData(vData.parray, (void**)&fDatas );
-
- m_Data.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%f",&fData);
-
- fDatas[0]=fData;
-
- SafeArrayUnaccessData(vData.parray);
-
- }
-
- else
-
- {
-
- vData.vt = VT_I4 | VT_ARRAY;
-
- vData.parray=SafeArrayCreateVector(VT_I4, 0, 255 );
-
-
-
- long *lngDatas,lngData;
-
- SafeArrayAccessData(vData.parray, (void**)&lngDatas );
-
- m_Data.GetWindowText(strAddr,255);
-
- sscanf(strAddr,"%ld",&lngData);
-
- lngDatas[0]=lngData;
-
- SafeArrayUnaccessData(vData.parray);
-
- }
-
-
-
- lngRet=m_PPI.WriteData(lngDataAddr,(const VARIANT &)vData,1,m_DataMode.GetCurSel(),DataType,lngFixAddr);
-
- if(lngRet!=0)
-
- {
-
- m_Data.SetWindowText(_T("ERROR"));
-
- }
-
- SafeArrayUnaccessData(vData.parray);
-
- SafeArrayDestroy(vData.parray);
-
- VariantClear(&vData);
-
- }
-
-
-
详细的示例请在下面的链接下载:
早期版本的控件下载链接:
本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/323423,如需转载请自行联系原作者