叶帆工作室

嵌入式开发爱好者(十年开发经验,精通C/C++/VC/VB/C#...)

刘洪峰ID:yefanqiu
459935次访问,排名85好友0人,关注者117
微软MVP / CSDN 2008十大MVB
yefanqiu的文章
原创 207 篇
翻译 0 篇
转载 3 篇
评论 925 篇
叶帆的公告
本博客原创文章,作者保留一切权利,需经作者同意后方可转载,转载时 请注明[叶帆工作室]及文章链接。yefan@vip.sina.com
【简介】叶帆[微软MVP]
【文章】叶帆文章列表
【软件】叶帆共享软件列表
最近评论
yefanqiu:如果你仅对串口、网口通信、IO感兴趣,建议买最便宜的板子,就是我blog上介绍的那种。如果你对图像感兴趣,可以考虑购买飞思卡尔的开发板。详细情况你可以登录他们的网站看看。
jacle169:digi很多产品,我应该买那个类型型号的测试板卡呢?!
yefanqiu:你可以联系Digi买它的测试板卡,当然也可以用模拟器,我曾经上传了一个可以调试IO的模拟器(CSDN下载)。
yefanqiu:仅是一个示例,绘图时采用双缓冲就不会闪了
zszzju:抖动的太厉害了。
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes
文章分类
收藏
    相册
    叶帆照片
    【叶帆软件】
    [01]VB源码之友(V2.1.548)
    [02]API浏览器.net(V5.0)
    [03]叶帆成语词典(V2.0.8)
    [04]叶帆密码库(V1.2.8)
    【叶帆资源】
    DAO 2.0引擎
    叶帆快速通道
    Windows Embedded 专题
    中文MSDN
    叶帆圈子--工业自动化
    叶帆工作室(博客园)
    叶帆工控--工业自动化
    叶帆群组--工业应用开发
    微软中文技术论坛
    瑞康社区论坛
    叶帆友情链接
    张欣
    枕善居
    莫依
    葛涵涛
    郑建
    马宁
    马骐
    黎波
    存档

    原创 Variant类型在各语言中的参数传递

    新一篇: .Net Micro Framework 2007技术论坛(提供PPT下载)

    几年前我用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)  //数据类型

                {

                    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.Se