1. 程式人生 > >Variant型別在各語言中的引數傳遞

Variant型別在各語言中的引數傳遞

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

幾年前我用VB開發了一個西門子PPI通訊控制元件,由於VB開發的控制元件是標準的COM元件,所以想當然的認為VCC#Delphi等開發語言可以非常容易的使用。

前段時間由於該控制元件基於微軟的

MSCOMM控制元件,這個控制元件如果系統沒有安裝VB,單獨註冊好像很難成功,這害的一些沒有裝VB的使用者,為了這個小控制元件必須安裝一次VB,這實在是划算不來,所以直接用API串列埠函式進行了封裝改進,這樣不僅效率提高了,並且再也不需要MSCOMM控制元件了。

這一次,我不僅使該控制元件支援了浮點運算,並且在VCC#VB當然就不用多試了,以前就很好的支援)進行了相容測試。

一試問題就來了,沒有改進之前的控制元件,由於C#封裝效能甚好,還能使用,唯一不足的是,控制元件方法中如果不要求返回的引數前面沒有新增ByVal引數,在C#中就轉換為 ref ***,害的你還得專門定義臨時變數進行傳參。

VC中直接就不行,ReadDataWriteData等幾個主要方法根本在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控制元件各語言肯定都能很好的支援,它的介面引數是怎樣的定義的。我在VBVCC#分別試了一下,VB中和inputOutput屬性的型別就是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開發的,VBC#的包容性都很強,而VC卻高高在上不肯屈就。

正一籌莫展準備放棄的時候,突然想到了以前用VC開發的OPC程式,上面有很多關於VARIANT的應用,一看就明白了,原來在VCVARIANT的用法是有講究的。

下面我就詳細說一下控制元件同樣的介面在不同語言中如何使用。

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#中:

/// <summary>

        /// 讀資料

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnRead_Click(object sender, EventArgs e)

        {

            int intAddr = int.Parse(txtFixAddr.Text);

            object vData = new object();

          

            /*

            [PPI_I] = &H81

            [PPI_Q] = &H82

            [PPI_M] = &H83

            [PPI_V] = &H84

            [PPI_S] = 4

            [PPI_SM] = 5

            */

            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";

            }

        }

 

        /// <summary>

        /// 寫資料

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnWrite_Click(object sender, EventArgs e)

        {        

 

            int intAddr = int.Parse(txtFixAddr.Text);

            object vData = new object();

 

            /*

            [PPI_I] = &H81

            [PPI_Q] = &H82

            [PPI_M] = &H83

            [PPI_V] = &H84

            [PPI_S] = 4

            [PPI_SM] = 5

            */

            PPIV2.PPITYPE DataType = PPIV2.PPITYPE.PPI_V;

            switch (cmbDataType.SelectedIndex)  //

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述