用实例讲解Variant类型在VB、C#、VC中的参数传递

前端之家收集整理的这篇文章主要介绍了用实例讲解Variant类型在VB、C#、VC中的参数传递前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

  几年前我用VB开发了一个西门子PPI通信控件,由于VB开发的控件是标准的COM组件,所以想当然的认为VC、C#、Delphi等开发语言可以非常容易的使用。

  前段时间由于该控件基于微软的MSCOMM控件,这个控件如果系统没有安装VB,单独注册好像很难成功,这害的一些没有装VB的用户,为了这个小控件必须安装一次VB,这实在是划算不来,所以直接用API串口函数进行了封装改进,这样不仅效率提高了,并且再也不需要MSCOMM控件了。

  这一次,我不仅使该控件支持了浮点运算,并且在VC、C#(VB当然就不用多试了,以前就很好的支持)进行了兼容测试。

  一试问题就来了,没有改进之前的控件,由于C#封装性能甚好,还能使用,唯一不足的是,控件方法中如果不要求返回的参数前面没有添加ByVal参数,在C#中就转换为 ref ***,害的你还得专门定义临时变量进行传参。

  在VC中直接就不行,ReadData和WriteData等几个主要方法根本在VC中无法转换成对应函数,具体错误信息如下:

// method 'ReadData' not emitted because of invalid return type or parameter type

// method 'WriteData' not emitted because of invalid return type or parameter type

// method 'PlcLogin' not emitted because of invalid return type or parameter type

// method 'PlcRun' not emitted because of invalid return type or parameter type

// method 'PlcStop' not emitted because of invalid return type or parameter type

  经过测试,最后发现VB函数中的byte和数组在VC中根本找不到合适的对应。

  由于控件中又新添加了浮点数的支持,所以对参数接口又增加了一层复杂性。突然想到微软的MSCOMM控件各语言肯定都能很好的支持,它的接口参数是怎样的定义的。我在VB、VC、C#分别试了一下,VB中和input和Output属性的类型就是Variant类型,在VC中是VARIANT,在C#中是Object。用Variant还有个好处,就是各种类型的数据都可以传输,没有必要在另外添加接口函数了。

  最后我定义的接口如下(主要接口):

  1. 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
  2.  
  3. Public Function WriteData(ByVal lngAddr As Long,ByVal vData As Variant,Optional ByVal Addr As Long = 0) As Long
  4. @H_403_28@

  5.   VC中对应的接口如下:
  6. long ReadData(long lngAddr,VARIANT* vData,long lngNum,long bytLen,long bytType,long Addr);
  7. long WriteData(long lngAddr,const VARIANT& vData,long Addr);
  8. @H_403_28@ 

  9.   C#中的接口如下:
  10.  
  11.      public virtual int ReadData(int lngAddr,ref object vData);
  12.      public virtual int ReadData(int lngAddr,ref object vData,int lngNum,PPILEN bytLen,PPITYPE bytType,int addr);
  13.        public virtual int WriteData(int lngAddr,object vData);
  14.    public virtual int WriteData(int lngAddr,object vData,int addr);
  15. @H_403_28@ 

  16.   以为这样定义就万事大吉了,事后一试我又错了,在C#中没有任何问题(看了微软还是在C#上下了很大的功夫),在VC简单的定义一个VARIANT变量直接传递给控件,VB控件老是报错,根本无法使用。后来想为什么MSCOMM控件可以,我的控件不可以。天杀的MSCOMM肯定是VC开发的,而我的控件是VB开发的,VB和C#的包容性都很强,而VC却高高在上不肯屈就。
  17.  
  18.   正一筹莫展准备放弃的时候,突然想到了以前用VC开发的OPC程序,上面有很多关于VARIANT的应用,一看就明白了,原来在VCVARIANT用法是有讲究的。

  19.   下面我就详细说一下控件同样的接口在不同语言中如何使用。

  20. VB中:

  21. Private Sub cmdReadData_Click()
  22.     On Error GoTo ToExit '打开错误陷阱
  23.     '------------------------------------------------
  24.     Dim i As Long
  25.     Dim bytType As Byte
  26.     Dim lngRet As Long
  27.     Dim lngData() As Long
  28.     Dim fData() As Single
  29.     Dim vData As Variant
  30.     Select Case cmbType.ListIndex
  31.     Case 0: bytType = PPI_I
  32.     Case 1: bytType = PPI_Q
  33.     Case 2: bytType = PPI_M
  34.     Case 3: bytType = PPI_V
  35.     Case 4: bytType = PPI_S
  36.     Case 5: bytType = PPI_SM
  37.     End Select
  38.     S7_PPI1.FixAddr = cmbNo.ListIndex + 1
  39.     lngRet = S7_PPI1.ReadData(Val(txtAddr),vData,Val(cmbNum.Text),Val(cmbLen.ListIndex),Val(bytType))
  40.     If lngRet = 0 Then
  41.         txtData = ""
  42.         If cmbLen.ListIndex = 3 Then
  43.             fData = vData
  44.             For i = 1 To Val(cmbNum.Text)
  45.                 txtData = txtData & Format(fData(i - 1),"0.00") & " "
  46.             Next
  47.         Else
  48.             lngData = vData
  49.             For i = 1 To Val(cmbNum.Text)
  50.                 txtData = txtData & Format(lngData(i - 1),"0") & " "
  51.             Next
  52.         End If
  53.     Else
  54.         txtData = "Error"
  55.     End If
  56.     '------------------------------------------------
  57.     Exit Sub
  58.     '----------------
  59. ToExit:
  60.     MsgBox Err.Description
  61. End Sub
  62. Private Sub cmdWriteData_Click()
  63.     On Error GoTo ToExit '打开错误陷阱
  64.     '------------------------------------------------
  65.     Dim bytType As Byte
  66.     Dim strData() As String
  67.     Dim lngRet As Long
  68.     Dim lngData(100) As Long
  69.     Dim fData(100) As Single
  70.     Dim i As Long
  71.     Select Case cmbType.ListIndex
  72.     Case 0: bytType = PPI_I
  73.     Case 1: bytType = PPI_Q
  74.     Case 2: bytType = PPI_M
  75.     Case 3: bytType = PPI_V
  76.     Case 4: bytType = PPI_S
  77.     Case 5: bytType = PPI_SM
  78.     End Select
  79.     If Len(txtData) > 0 Then
  80.         strData = Split(txtData," ")
  81.         If cmbLen.ListIndex = 3 Then
  82.             For i = 0 To UBound(strData)
  83.                 fData(i) = Val(strData(i))
  84.             Next
  85.             lngRet = S7_PPI1.WriteData(Val(txtAddr),fData,UBound(strData) + 1,Val(bytType),cmbNo.ListIndex + 1)
  86.         Else
  87.             For i = 0 To UBound(strData)
  88.                 lngData(i) = Val(strData(i))
  89.             Next
  90.             lngRet = S7_PPI1.WriteData(Val(txtAddr),lngData,cmbNo.ListIndex + 1)
  91.         End If
  92.         If lngRet = 0 Then
  93.             '
  94.         Else
  95.             txtData = "Error"
  96.         End If
  97.     End If
  98.     '------------------------------------------------
  99.     Exit Sub
  100.     '----------------
  101. ToExit:
  102.     MsgBox Err.Description
  103. End Sub
  104. @H_403_28@ 


  105.  
  106. 在C#中:

  107. /// <summary>
  108.         /// 读数据
  109.         /// </summary>
  110.         /// <param name="sender"></param>
  111.         /// <param name="e"></param>
  112.         private void btnRead_Click(object sender,EventArgs e)
  113.         {
  114.             int intAddr = int.Parse(txtFixAddr.Text);
  115.             object vData = new object();
  116.           
  117.             /*
  118.             [PPI_I] = &H81
  119.             [PPI_Q] = &H82
  120.             [PPI_M] = &H83
  121.             [PPI_V] = &H84
  122.             [PPI_S] = 4
  123.             [PPI_SM] = 5
  124.             */
  125.             PPIV2.PPITYPE DataType= PPIV2.PPITYPE.PPI_V;
  126.             switch (cmbDataType.SelectedIndex)  //数据类型
  127.             {
  128.                 case 0:
  129.                     DataType = PPIV2.PPITYPE.PPI_I;
  130.                     break;
  131.                 case 1:
  132.                     DataType = PPIV2.PPITYPE.PPI_Q;
  133.                     break;
  134.                 case 2:
  135.                     DataType = PPIV2.PPITYPE.PPI_M;
  136.                     break;
  137.                 case 3:
  138.                     DataType = PPIV2.PPITYPE.PPI_V;
  139.                     break;
  140.                 case 4:
  141.                     DataType = PPIV2.PPITYPE.PPI_S;
  142.                     break;
  143.                 case 5:
  144.                     DataType = PPIV2.PPITYPE.PPI_SM;
  145.                     break;
  146.             }
  147.             if (axS7_PPI1.ReadData(int.Parse(txtDataAddr.Text),ref vData,cmbLen.SelectedIndex+1,(PPIV2.PPILEN)cmbDataMode.SelectedIndex,DataType,intAddr) == 0)
  148.             {
  149.                 if (cmbDataMode.SelectedIndex == 3)
  150.                 {
  151.                     float[] fData = (float[])vData;
  152.                     txtData.Text = "";
  153.                     for (int i = 0; i < fData.Length; i++)
  154.                     {
  155.                         txtData.Text += fData[i].ToString("0.00") + " ";
  156.                     }
  157.                 }
  158.                 else
  159.                 {
  160.                     Int32[] intData = (Int32[])vData;
  161.                     txtData.Text = "";
  162.                     for (int i = 0; i < intData.Length; i++)
  163.                     {
  164.                         txtData.Text += intData[i].ToString() + " ";
  165.                     }
  166.                 }
  167.             }
  168.             else
  169.             {
  170.                 txtData.Text = "ERROR";
  171.             }
  172.         }
  173.  
  174.         /// <summary>
  175.         /// 写数据
  176.         /// </summary>
  177.         /// <param name="sender"></param>
  178.         /// <param name="e"></param>
  179.         private void btnWrite_Click(object sender,EventArgs e)
  180.         {        
  181.  
  182.             int intAddr = int.Parse(txtFixAddr.Text);
  183.             object vData = new object();
  184.  
  185.             /*
  186.             [PPI_I] = &H81
  187.             [PPI_Q] = &H82
  188.             [PPI_M] = &H83
  189.             [PPI_V] = &H84
  190.             [PPI_S] = 4
  191.             [PPI_SM] = 5
  192.             */
  193.             PPIV2.PPITYPE DataType = PPIV2.PPITYPE.PPI_V;
  194.             switch (cmbDataType.SelectedIndex)  //数据类型
  195.             {
  196.                 case 0:
  197.                     DataType = PPIV2.PPITYPE.PPI_I;
  198.                     break;
  199.                 case 1:
  200.                     DataType = PPIV2.PPITYPE.PPI_Q;
  201.                     break;
  202.                 case 2:
  203.                     DataType = PPIV2.PPITYPE.PPI_M;
  204.                     break;
  205.                 case 3:
  206.                     DataType = PPIV2.PPITYPE.PPI_V;
  207.                     break;
  208.                 case 4:
  209.                     DataType = PPIV2.PPITYPE.PPI_S;
  210.                     break;
  211.                 case 5:
  212.                     DataType = PPIV2.PPITYPE.PPI_SM;
  213.                     break;
  214.             }
  215.             long lngRet = 0;
  216.             if (cmbDataMode.SelectedIndex == 3)
  217.             {
  218.                 float[] fData = new float[100];
  219.                 fData[0] = float.Parse(txtData.Text);
  220.                 lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text),1,intAddr);
  221.             }
  222.             else
  223.             {
  224.                 Int32[] intData = new Int32[100];
  225.                 intData[0] = Int32.Parse(txtData.Text);
  226.                 lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text),intData,intAddr);
  227.             }
  228.             if (lngRet != 0)
  229.             {
  230.                 txtData.Text = "ERROR";
  231.             }
  232.         }
  233. @H_403_28@ 


  234. 在VC中:
  235.  


  236. //读数据
  237. void CPPI_TestDlg::OnReadData()
  238. {
  239.        //pCombo->GetLBText (pCombo->GetCurSel (),strType);
  240.        long lngFixAddr=0,lngDataAddr=0;
  241.        char strAddr[255];
  242.        m_FixAddr.GetWindowText(strAddr,255);
  243.        sscanf(strAddr,"%ld",&lngFixAddr);
  244.       
  245.        m_DataAddr.GetWindowText(strAddr,&lngDataAddr);
  246.     /*
  247.        [PPI_I] = &H81
  248.     [PPI_Q] = &H82
  249.     [PPI_M] = &H83
  250.     [PPI_V] = &H84
  251.     [PPI_S] = 4
  252.     [PPI_SM] = 5
  253.        */
  254.     long DataType;
  255.        switch (m_DataType.GetCurSel())  //数据类型
  256.        {
  257.        case 0:
  258.               DataType=0x81; 
  259.               break;
  260.        case 1:
  261.               DataType=0x82;
  262.               break;
  263.        case 2:
  264.               DataType=0x83;
  265.               break;
  266.        case 3:
  267.               DataType=0x84;
  268.               break;
  269.        case 4:
  270.               DataType=0x4;
  271.               break;
  272.        case 5:
  273.               DataType=0x5;
  274.               break;
  275.        }
  276.  
  277.        long lngRet;
  278.     VARIANT vData;
  279.        VariantInit (&vData);
  280.        if(m_DataMode.GetCurSel()==3)  //浮点数
  281.        {
  282.            vData.vt = VT_R4 | VT_ARRAY;
  283.            vData.parray=SafeArrayCreateVector(VT_R4,255 );    
  284.        }
  285.        else
  286.        {
  287.            vData.vt = VT_I4 | VT_ARRAY;
  288.            vData.parray=SafeArrayCreateVector(VT_I4,255 );     //SAFEARRAY vd;
  289.        }   
  290.        lngRet=m_PPI.ReadData(lngDataAddr,&vData,m_Datanum.GetCurSel()+1,m_DataMode.GetCurSel(),lngFixAddr);
  291.        if(lngRet==0)
  292.        {
  293.               CString strData;
  294.               if(m_DataMode.GetCurSel()==3)  //浮点数
  295.               {
  296.                      float *fData;
  297.                      SafeArrayAccessData(vData.parray,(void**)&fData );
  298.                      for(int i=0;i<m_Datanum.GetCurSel()+1;i++)  //(int)vData.parray->cbElements
  299.                      {
  300.                         CString cData;
  301.                         cData.Format("%04.2f ",fData[i]);
  302.                         strData+= cData;
  303.                      }
  304.                      SafeArrayUnaccessData(vData.parray);
  305.               }
  306.               else
  307.               {
  308.                      long *lngData;
  309.                      SafeArrayAccessData(vData.parray,(void**)&lngData );
  310.                      for(int i=0;i<m_Datanum.GetCurSel()+1;i++)  //(int)vData.parray->cbElements
  311.                      {
  312.                         CString cData;
  313.                         cData.Format("%ld ",lngData[i]);
  314.                         strData+= cData;
  315.                      }
  316.                      SafeArrayUnaccessData(vData.parray);
  317.               }
  318.  
  319.               m_Data.SetWindowText(strData);
  320.        }
  321.        else
  322.        {
  323.         m_Data.SetWindowText(_T("ERROR"));
  324.        }
  325.        SafeArrayUnaccessData(vData.parray);
  326.        SafeArrayDestroy(vData.parray);
  327.     VariantClear(&vData);
  328. }
  329.  
  330. //写数据
  331. void CPPI_TestDlg::OnWrite()
  332. {
  333.        long lngFixAddr=0,&lngDataAddr);
  334.  
  335.     long DataType;
  336.        switch (m_DataType.GetCurSel())
  337.        {
  338.        case 0:
  339.               DataType=0x81;
  340.               break;
  341.        case 1:
  342.               DataType=0x82;
  343.               break;
  344.        case 2:
  345.               DataType=0x83;
  346.               break;
  347.        case 3:
  348.               DataType=0x84;
  349.               break;
  350.        case 4:
  351.               DataType=0x4;
  352.               break;
  353.        case 5:
  354.               DataType=0x5;
  355.               break;
  356.        }
  357.        long lngRet;
  358.     VARIANT vData;
  359.        VariantInit (&vData);
  360.        if(m_DataMode.GetCurSel()==3)  //浮点数
  361.        {
  362.            vData.vt = VT_R4 | VT_ARRAY;
  363.            vData.parray=SafeArrayCreateVector(VT_R4,255 );
  364.              
  365.               float *fDatas,fData;
  366.               SafeArrayAccessData(vData.parray,(void**)&fDatas );
  367.               m_Data.GetWindowText(strAddr,255);
  368.               sscanf(strAddr,"%f",&fData);
  369.               fDatas[0]=fData;
  370.               SafeArrayUnaccessData(vData.parray);
  371.        }
  372.        else
  373.        {
  374.            vData.vt = VT_I4 | VT_ARRAY;
  375.            vData.parray=SafeArrayCreateVector(VT_I4,255 );     //SAFEARRAY vd;
  376.              
  377.               long *lngDatas,lngData;
  378.               SafeArrayAccessData(vData.parray,(void**)&lngDatas );
  379.               m_Data.GetWindowText(strAddr,&lngData);
  380.               lngDatas[0]=lngData;
  381.               SafeArrayUnaccessData(vData.parray);
  382.        }
  383.  
  384.     lngRet=m_PPI.WriteData(lngDataAddr,(const VARIANT &)vData,lngFixAddr);
  385.        if(lngRet!=0)
  386.        {
  387.               m_Data.SetWindowText(_T("ERROR"));
  388.        }
  389.        SafeArrayUnaccessData(vData.parray);
  390.        SafeArrayDestroy(vData.parray);
  391.     VariantClear(&vData);
  392. }@H_403_28@

猜你在找的VB相关文章